1
1
import * as React from 'react' ;
2
2
import classNames from 'classnames' ;
3
3
import type { Placement } from './Drawer' ;
4
+ import KeyCode from 'rc-util/lib/KeyCode' ;
5
+
6
+ export interface DrawerPanelRef {
7
+ focus : VoidFunction ;
8
+ }
4
9
5
10
export interface DrawerPanelProps {
6
11
prefixCls : string ;
@@ -11,18 +16,88 @@ export interface DrawerPanelProps {
11
16
children ?: React . ReactNode ;
12
17
}
13
18
14
- export default function DrawerPanel ( props : DrawerPanelProps ) {
15
- const { prefixCls, className, style, placement, width, children } = props ;
16
-
17
- return (
18
- < div
19
- className = { classNames ( `${ prefixCls } -panel` , className ) }
20
- style = { {
21
- width : placement === 'left' || placement === 'right' ? width : '100%' ,
22
- ...style ,
23
- } }
24
- >
25
- { children }
26
- </ div >
27
- ) ;
19
+ const sentinelStyle : React . CSSProperties = {
20
+ width : 0 ,
21
+ height : 0 ,
22
+ overflow : 'hidden' ,
23
+ outline : 'none' ,
24
+ position : 'absolute' ,
25
+ } ;
26
+
27
+ const DrawerPanel = React . forwardRef < DrawerPanelRef , DrawerPanelProps > (
28
+ ( props , ref ) => {
29
+ const { prefixCls, className, style, placement, width, children } = props ;
30
+
31
+ // ================================ Refs ================================
32
+ const panelRef = React . useRef < HTMLDivElement > ( ) ;
33
+ const sentinelStartRef = React . useRef < HTMLDivElement > ( ) ;
34
+ const sentinelEndRef = React . useRef < HTMLDivElement > ( ) ;
35
+
36
+ React . useImperativeHandle ( ref , ( ) => ( {
37
+ focus : ( ) => {
38
+ Promise . resolve ( ) . then ( ( ) => {
39
+ sentinelStartRef . current ?. focus ( { preventScroll : true } ) ;
40
+ } ) ;
41
+ } ,
42
+ } ) ) ;
43
+
44
+ const onPanelKeyDown : React . KeyboardEventHandler < HTMLDivElement > = ( {
45
+ keyCode,
46
+ shiftKey,
47
+ } ) => {
48
+ switch ( keyCode ) {
49
+ case KeyCode . TAB : {
50
+ if ( ! shiftKey && document . activeElement === sentinelEndRef . current ) {
51
+ sentinelStartRef . current ?. focus ( { preventScroll : true } ) ;
52
+ } else if (
53
+ shiftKey &&
54
+ document . activeElement === sentinelStartRef . current
55
+ ) {
56
+ sentinelEndRef . current ?. focus ( { preventScroll : true } ) ;
57
+ }
58
+ }
59
+ }
60
+ } ;
61
+
62
+ // =============================== Render ===============================
63
+ return (
64
+ < >
65
+ < div
66
+ className = { classNames ( `${ prefixCls } -panel` , className ) }
67
+ style = { {
68
+ width :
69
+ placement === 'left' || placement === 'right' ? width : '100%' ,
70
+ ...style ,
71
+ } }
72
+ aria-modal = "true"
73
+ role = "dialog"
74
+ tabIndex = { - 1 }
75
+ ref = { panelRef }
76
+ onKeyDown = { onPanelKeyDown }
77
+ >
78
+ < div
79
+ tabIndex = { 0 }
80
+ ref = { sentinelStartRef }
81
+ style = { sentinelStyle }
82
+ aria-hidden = "true"
83
+ />
84
+
85
+ { children }
86
+
87
+ < div
88
+ tabIndex = { 0 }
89
+ ref = { sentinelEndRef }
90
+ style = { sentinelStyle }
91
+ aria-hidden = "true"
92
+ />
93
+ </ div >
94
+ </ >
95
+ ) ;
96
+ } ,
97
+ ) ;
98
+
99
+ if ( process . env . NODE_ENV === 'development' ) {
100
+ DrawerPanel . displayName = 'DrawerPanel' ;
28
101
}
102
+
103
+ export default DrawerPanel ;
0 commit comments