1
1
import PropTypes from 'prop-types' ;
2
- import React from 'react' ;
2
+ import React , { useCallback , useRef } from 'react' ;
3
+ import { useSelector } from 'react-redux' ;
3
4
import { browserHistory } from 'react-router' ;
4
- import { withTranslation } from 'react-i18next' ;
5
+ import { useTranslation } from 'react-i18next' ;
6
+ import useModalClose from '../../../common/useModalClose' ;
5
7
6
8
import ExitIcon from '../../../images/exit.svg' ;
7
9
8
- class Overlay extends React . Component {
9
- constructor ( props ) {
10
- super ( props ) ;
11
- this . close = this . close . bind ( this ) ;
12
- this . handleClick = this . handleClick . bind ( this ) ;
13
- this . handleClickOutside = this . handleClickOutside . bind ( this ) ;
14
- this . keyPressHandle = this . keyPressHandle . bind ( this ) ;
15
- }
10
+ const Overlay = ( {
11
+ actions,
12
+ ariaLabel,
13
+ children,
14
+ closeOverlay,
15
+ isFixedHeight,
16
+ title
17
+ } ) => {
18
+ const { t } = useTranslation ( ) ;
16
19
17
- componentWillMount ( ) {
18
- document . addEventListener ( 'mousedown' , this . handleClick , false ) ;
19
- document . addEventListener ( 'keydown' , this . keyPressHandle ) ;
20
- }
20
+ const previousPath = useSelector ( ( state ) => state . ide . previousPath ) ;
21
21
22
- componentDidMount ( ) {
23
- this . node . focus ( ) ;
24
- }
22
+ const ref = useRef ( null ) ;
25
23
26
- componentWillUnmount ( ) {
27
- document . removeEventListener ( 'mousedown' , this . handleClick , false ) ;
28
- document . removeEventListener ( 'keydown' , this . keyPressHandle ) ;
29
- }
30
-
31
- handleClick ( e ) {
32
- if ( this . node . contains ( e . target ) ) {
33
- return ;
34
- }
35
-
36
- this . handleClickOutside ( e ) ;
37
- }
38
-
39
- handleClickOutside ( ) {
40
- this . close ( ) ;
41
- }
42
-
43
- keyPressHandle ( e ) {
44
- // escape key code = 27.
45
- // So here we are checking if the key pressed was Escape key.
46
- if ( e . keyCode === 27 ) {
47
- this . close ( ) ;
48
- }
49
- }
50
-
51
- close ( ) {
24
+ const close = useCallback ( ( ) => {
25
+ const node = ref . current ;
26
+ if ( ! node ) return ;
52
27
// Only close if it is the last (and therefore the topmost overlay)
53
28
const overlays = document . getElementsByClassName ( 'overlay' ) ;
54
- if ( this . node . parentElement . parentElement !== overlays [ overlays . length - 1 ] )
29
+ if ( node . parentElement . parentElement !== overlays [ overlays . length - 1 ] )
55
30
return ;
56
31
57
- if ( ! this . props . closeOverlay ) {
58
- browserHistory . push ( this . props . previousPath ) ;
32
+ if ( ! closeOverlay ) {
33
+ browserHistory . push ( previousPath ) ;
59
34
} else {
60
- this . props . closeOverlay ( ) ;
35
+ closeOverlay ( ) ;
61
36
}
62
- }
37
+ } , [ previousPath , closeOverlay , ref ] ) ;
63
38
64
- render ( ) {
65
- const { ariaLabel, title, children, actions, isFixedHeight } = this . props ;
66
- return (
67
- < div
68
- className = { `overlay ${ isFixedHeight ? 'overlay--is-fixed-height' : '' } ` }
69
- >
70
- < div className = "overlay__content" >
71
- < section
72
- role = "main"
73
- aria-label = { ariaLabel }
74
- ref = { ( node ) => {
75
- this . node = node ;
76
- } }
77
- className = "overlay__body"
78
- >
79
- < header className = "overlay__header" >
80
- < h2 className = "overlay__title" > { title } </ h2 >
81
- < div className = "overlay__actions" >
82
- { actions }
83
- < button
84
- className = "overlay__close-button"
85
- onClick = { this . close }
86
- aria-label = { this . props . t ( 'Overlay.AriaLabel' , { title } ) }
87
- >
88
- < ExitIcon focusable = "false" aria-hidden = "true" />
89
- </ button >
90
- </ div >
91
- </ header >
92
- { children }
93
- </ section >
94
- </ div >
39
+ useModalClose ( close , ref ) ;
40
+
41
+ return (
42
+ < div
43
+ className = { `overlay ${ isFixedHeight ? 'overlay--is-fixed-height' : '' } ` }
44
+ >
45
+ < div className = "overlay__content" >
46
+ < section
47
+ role = "main"
48
+ aria-label = { ariaLabel }
49
+ ref = { ref }
50
+ className = "overlay__body"
51
+ >
52
+ < header className = "overlay__header" >
53
+ < h2 className = "overlay__title" > { title } </ h2 >
54
+ < div className = "overlay__actions" >
55
+ { actions }
56
+ < button
57
+ className = "overlay__close-button"
58
+ onClick = { close }
59
+ aria-label = { t ( 'Overlay.AriaLabel' , { title } ) }
60
+ >
61
+ < ExitIcon focusable = "false" aria-hidden = "true" />
62
+ </ button >
63
+ </ div >
64
+ </ header >
65
+ { children }
66
+ </ section >
95
67
</ div >
96
- ) ;
97
- }
98
- }
68
+ </ div >
69
+ ) ;
70
+ } ;
99
71
100
72
Overlay . propTypes = {
101
73
children : PropTypes . element ,
102
74
actions : PropTypes . element ,
103
75
closeOverlay : PropTypes . func ,
104
76
title : PropTypes . string ,
105
77
ariaLabel : PropTypes . string ,
106
- previousPath : PropTypes . string ,
107
- isFixedHeight : PropTypes . bool ,
108
- t : PropTypes . func . isRequired
78
+ isFixedHeight : PropTypes . bool
109
79
} ;
110
80
111
81
Overlay . defaultProps = {
@@ -114,8 +84,7 @@ Overlay.defaultProps = {
114
84
title : 'Modal' ,
115
85
closeOverlay : null ,
116
86
ariaLabel : 'modal' ,
117
- previousPath : '/' ,
118
87
isFixedHeight : false
119
88
} ;
120
89
121
- export default withTranslation ( ) ( Overlay ) ;
90
+ export default Overlay ;
0 commit comments