1
- import React , { useRef } from 'react' ;
1
+ import React , { useRef , useEffect } from 'react' ;
2
2
import classNames from 'classnames' ;
3
3
import { useTranslation } from 'react-i18next' ;
4
4
import { useDispatch , useSelector } from 'react-redux' ;
@@ -30,21 +30,38 @@ export default function SideBar() {
30
30
) ;
31
31
const isExpanded = useSelector ( ( state ) => state . ide . sidebarIsExpanded ) ;
32
32
const canEditProject = useSelector ( selectCanEditSketch ) ;
33
+ const isAuthenticated = useSelector ( getAuthenticated ) ;
33
34
34
35
const sidebarOptionsRef = useRef ( null ) ;
35
36
36
- const isAuthenticated = useSelector ( getAuthenticated ) ;
37
+ /** Close dropdown when clicking outside */
38
+ useEffect ( ( ) => {
39
+ function handleClickOutside ( event ) {
40
+ if (
41
+ projectOptionsVisible &&
42
+ sidebarOptionsRef . current &&
43
+ ! sidebarOptionsRef . current . contains ( event . target )
44
+ ) {
45
+ setTimeout ( ( ) => dispatch ( closeProjectOptions ( ) ) , 300 ) ;
46
+ }
47
+ }
37
48
38
- const onBlurComponent = ( ) => {
39
- setTimeout ( ( ) => dispatch ( closeProjectOptions ( ) ) , 200 ) ;
40
- } ;
49
+ if ( projectOptionsVisible ) {
50
+ document . addEventListener ( 'mousedown' , handleClickOutside ) ;
51
+ } else {
52
+ document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
53
+ }
54
+
55
+ return ( ) => {
56
+ document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
57
+ } ;
58
+ } , [ projectOptionsVisible , dispatch ] ) ;
41
59
42
60
const toggleProjectOptions = ( e ) => {
43
61
e . preventDefault ( ) ;
44
62
if ( projectOptionsVisible ) {
45
63
dispatch ( closeProjectOptions ( ) ) ;
46
64
} else {
47
- sidebarOptionsRef . current ?. focus ( ) ;
48
65
dispatch ( openProjectOptions ( ) ) ;
49
66
}
50
67
} ;
@@ -65,69 +82,61 @@ export default function SideBar() {
65
82
dispatch ( collapseSidebar ( ) ) ;
66
83
dispatch ( closeProjectOptions ( ) ) ;
67
84
} }
68
- >
69
- { ' ' }
70
- </ button >
85
+ />
71
86
) }
72
87
< section className = { sidebarClass } >
73
- < header
74
- className = "sidebar__header"
75
- onContextMenu = { toggleProjectOptions }
76
- >
88
+ < header className = "sidebar__header" >
77
89
< h3 className = "sidebar__title" >
78
90
< span > { t ( 'Sidebar.Title' ) } </ span >
79
91
</ h3 >
80
- < div className = "sidebar__icons" >
92
+ < div className = "sidebar__icons" ref = { sidebarOptionsRef } >
81
93
< button
82
94
aria-label = { t ( 'Sidebar.ToggleARIA' ) }
83
95
className = "sidebar__add"
84
96
tabIndex = "0"
85
- ref = { sidebarOptionsRef }
86
97
onClick = { toggleProjectOptions }
87
- onBlur = { onBlurComponent }
88
98
>
89
99
< PlusIcon focusable = "false" aria-hidden = "true" />
90
100
</ button >
91
- < ul className = "sidebar__project-options" >
92
- < li >
93
- < button
94
- onMouseDown = { ( e ) => e . preventDefault ( ) }
95
- aria-label = { t ( 'Sidebar.AddFolderARIA' ) }
96
- onClick = { ( ) => {
97
- dispatch ( newFolder ( rootFile . id ) ) ;
98
- } }
99
- onBlur = { onBlurComponent }
100
- >
101
- { t ( 'Sidebar.AddFolder' ) }
102
- </ button >
103
- </ li >
104
- < li >
105
- < button
106
- onMouseDown = { ( e ) => e . preventDefault ( ) }
107
- aria-label = { t ( 'Sidebar.AddFileARIA' ) }
108
- onClick = { ( ) => {
109
- dispatch ( newFile ( rootFile . id ) ) ;
110
- } }
111
- onBlur = { onBlurComponent }
112
- >
113
- { t ( 'Sidebar.AddFile' ) }
114
- </ button >
115
- </ li >
116
- { isAuthenticated && (
101
+ { projectOptionsVisible && (
102
+ < ul className = "sidebar__project-options" >
103
+ < li >
104
+ < button
105
+ aria-label = { t ( 'Sidebar.AddFolderARIA' ) }
106
+ onClick = { ( ) => {
107
+ dispatch ( newFolder ( rootFile . id ) ) ;
108
+ setTimeout ( ( ) => dispatch ( closeProjectOptions ( ) ) , 300 ) ;
109
+ } }
110
+ >
111
+ { t ( 'Sidebar.AddFolder' ) }
112
+ </ button >
113
+ </ li >
117
114
< li >
118
115
< button
119
- onMouseDown = { ( e ) => e . preventDefault ( ) }
120
- aria-label = { t ( 'Sidebar.UploadFileARIA' ) }
116
+ aria-label = { t ( 'Sidebar.AddFileARIA' ) }
121
117
onClick = { ( ) => {
122
- dispatch ( openUploadFileModal ( rootFile . id ) ) ;
118
+ dispatch ( newFile ( rootFile . id ) ) ;
119
+ setTimeout ( ( ) => dispatch ( closeProjectOptions ( ) ) , 300 ) ;
123
120
} }
124
- onBlur = { onBlurComponent }
125
121
>
126
- { t ( 'Sidebar.UploadFile ' ) }
122
+ { t ( 'Sidebar.AddFile ' ) }
127
123
</ button >
128
124
</ li >
129
- ) }
130
- </ ul >
125
+ { isAuthenticated && (
126
+ < li >
127
+ < button
128
+ aria-label = { t ( 'Sidebar.UploadFileARIA' ) }
129
+ onClick = { ( ) => {
130
+ dispatch ( openUploadFileModal ( rootFile . id ) ) ;
131
+ setTimeout ( ( ) => dispatch ( closeProjectOptions ( ) ) , 300 ) ;
132
+ } }
133
+ >
134
+ { t ( 'Sidebar.UploadFile' ) }
135
+ </ button >
136
+ </ li >
137
+ ) }
138
+ </ ul >
139
+ ) }
131
140
</ div >
132
141
</ header >
133
142
< ConnectedFileNode id = { rootFile . id } canEdit = { canEditProject } />
0 commit comments