11import PropTypes from 'prop-types' ;
2- import React from 'react' ;
3- import { withTranslation } from 'react-i18next' ;
2+ import React , { useCallback , useRef } from 'react' ;
3+ import { useSelector } from 'react-redux' ;
4+ import { useHistory } from 'react-router-dom' ;
5+ import { useTranslation } from 'react-i18next' ;
6+ import useModalClose from '../../../common/useModalClose' ;
47
5- import browserHistory from '../../../browserHistory' ;
68import ExitIcon from '../../../images/exit.svg' ;
7- import { DocumentKeyDown } from '../../IDE/hooks/useKeyDownHandlers' ;
89
9- class Overlay extends React . Component {
10- constructor ( props ) {
11- super ( props ) ;
12- this . close = this . close . bind ( this ) ;
13- this . handleClick = this . handleClick . bind ( this ) ;
14- this . handleClickOutside = this . handleClickOutside . bind ( this ) ;
15- }
10+ const Overlay = ( {
11+ actions,
12+ ariaLabel,
13+ children,
14+ closeOverlay,
15+ isFixedHeight,
16+ title
17+ } ) => {
18+ const { t } = useTranslation ( ) ;
1619
17- componentWillMount ( ) {
18- document . addEventListener ( 'mousedown' , this . handleClick , false ) ;
19- }
20+ const previousPath = useSelector ( ( state ) => state . ide . previousPath ) ;
2021
21- componentDidMount ( ) {
22- this . node . focus ( ) ;
23- }
22+ const ref = useRef ( null ) ;
2423
25- componentWillUnmount ( ) {
26- document . removeEventListener ( 'mousedown' , this . handleClick , false ) ;
27- }
24+ const browserHistory = useHistory ( ) ;
2825
29- handleClick ( e ) {
30- if ( this . node . contains ( e . target ) ) {
31- return ;
32- }
33-
34- this . handleClickOutside ( e ) ;
35- }
36-
37- handleClickOutside ( ) {
38- this . close ( ) ;
39- }
40-
41- close ( ) {
26+ const close = useCallback ( ( ) => {
27+ const node = ref . current ;
28+ if ( ! node ) return ;
4229 // Only close if it is the last (and therefore the topmost overlay)
4330 const overlays = document . getElementsByClassName ( 'overlay' ) ;
44- if ( this . node . parentElement . parentElement !== overlays [ overlays . length - 1 ] )
31+ if ( node . parentElement . parentElement !== overlays [ overlays . length - 1 ] )
4532 return ;
4633
47- if ( ! this . props . closeOverlay ) {
48- browserHistory . push ( this . props . previousPath ) ;
34+ if ( ! closeOverlay ) {
35+ browserHistory . push ( previousPath ) ;
4936 } else {
50- this . props . closeOverlay ( ) ;
37+ closeOverlay ( ) ;
5138 }
52- }
39+ } , [ previousPath , closeOverlay , ref ] ) ;
40+
41+ useModalClose ( close , ref ) ;
5342
54- render ( ) {
55- const { ariaLabel, title, children, actions, isFixedHeight } = this . props ;
56- return (
57- < div
58- className = { `overlay ${ isFixedHeight ? 'overlay--is-fixed-height' : '' } ` }
59- >
60- < div className = "overlay__content" >
61- < section
62- role = "main"
63- aria-label = { ariaLabel }
64- ref = { ( node ) => {
65- this . node = node ;
66- } }
67- className = "overlay__body"
68- >
69- < header className = "overlay__header" >
70- < h2 className = "overlay__title" > { title } </ h2 >
71- < div className = "overlay__actions" >
72- { actions }
73- < button
74- className = "overlay__close-button"
75- onClick = { this . close }
76- aria-label = { this . props . t ( 'Overlay.AriaLabel' , { title } ) }
77- >
78- < ExitIcon focusable = "false" aria-hidden = "true" />
79- </ button >
80- </ div >
81- </ header >
82- { children }
83- < DocumentKeyDown handlers = { { escape : ( ) => this . close ( ) } } />
84- </ section >
85- </ div >
43+ return (
44+ < div
45+ className = { `overlay ${ isFixedHeight ? 'overlay--is-fixed-height' : '' } ` }
46+ >
47+ < div className = "overlay__content" >
48+ < section
49+ role = "main"
50+ aria-label = { ariaLabel }
51+ ref = { ref }
52+ className = "overlay__body"
53+ >
54+ < header className = "overlay__header" >
55+ < h2 className = "overlay__title" > { title } </ h2 >
56+ < div className = "overlay__actions" >
57+ { actions }
58+ < button
59+ className = "overlay__close-button"
60+ onClick = { close }
61+ aria-label = { t ( 'Overlay.AriaLabel' , { title } ) }
62+ >
63+ < ExitIcon focusable = "false" aria-hidden = "true" />
64+ </ button >
65+ </ div >
66+ </ header >
67+ { children }
68+ </ section >
8669 </ div >
87- ) ;
88- }
89- }
70+ </ div >
71+ ) ;
72+ } ;
9073
9174Overlay . propTypes = {
9275 children : PropTypes . element ,
9376 actions : PropTypes . element ,
9477 closeOverlay : PropTypes . func ,
9578 title : PropTypes . string ,
9679 ariaLabel : PropTypes . string ,
97- previousPath : PropTypes . string ,
98- isFixedHeight : PropTypes . bool ,
99- t : PropTypes . func . isRequired
80+ isFixedHeight : PropTypes . bool
10081} ;
10182
10283Overlay . defaultProps = {
@@ -105,8 +86,7 @@ Overlay.defaultProps = {
10586 title : 'Modal' ,
10687 closeOverlay : null ,
10788 ariaLabel : 'modal' ,
108- previousPath : '/' ,
10989 isFixedHeight : false
11090} ;
11191
112- export default withTranslation ( ) ( Overlay ) ;
92+ export default Overlay ;
0 commit comments