1
- import React , { useCallback } from 'react' ;
1
+ import React , { RefObject , useCallback , useRef } from 'react' ;
2
2
import { useSelector } from 'react-redux' ;
3
3
4
4
import AdvancedOptionsMenu from './AdvancedOptionsMenu' ;
5
5
import BuildMenu from './BuildMenu' ;
6
+ import { ButtonSet , IconButton , IconLink , Button as OneButton , Rule } from './ButtonSet' ;
6
7
import ChannelMenu from './ChannelMenu' ;
7
8
import ConfigMenu from './ConfigMenu' ;
8
- import HeaderButton from './HeaderButton' ;
9
- import { BuildIcon , ConfigIcon , HelpIcon , MoreOptionsActiveIcon , MoreOptionsIcon } from './Icon' ;
9
+ import {
10
+ BuildIcon ,
11
+ ConfigIcon ,
12
+ ExpandableIcon ,
13
+ HelpIcon ,
14
+ MoreOptionsActiveIcon ,
15
+ MoreOptionsIcon ,
16
+ } from './Icon' ;
10
17
import ModeMenu from './ModeMenu' ;
11
- import PopButton from './PopButton' ;
12
- import { SegmentedButton , SegmentedButtonSet , SegmentedLink } from './SegmentedButton' ;
18
+ import PopButton , { ButtonProps } from './PopButton' ;
13
19
import ToolsMenu from './ToolsMenu' ;
14
-
15
20
import * as actions from './actions' ;
16
- import * as selectors from './selectors' ;
17
21
import { useAppDispatch } from './configureStore' ;
18
22
import { performGistSave } from './reducers/output/gist' ;
23
+ import * as selectors from './selectors' ;
19
24
20
25
import styles from './Header.module.css' ;
21
26
22
- const Header : React . FC = ( ) => (
23
- < div data-test-id = "header" className = { styles . container } >
24
- < HeaderSet id = "build" >
25
- < SegmentedButtonSet >
26
- < ExecuteButton />
27
- < BuildMenuButton />
28
- </ SegmentedButtonSet >
29
- </ HeaderSet >
30
- < HeaderSet id = "channel-mode" >
31
- < SegmentedButtonSet >
32
- < ModeMenuButton />
33
- < ChannelMenuButton />
34
- < AdvancedOptionsMenuButton />
35
- </ SegmentedButtonSet >
36
- </ HeaderSet >
37
- < HeaderSet id = "share" >
38
- < SegmentedButtonSet >
39
- < ShareButton />
40
- </ SegmentedButtonSet >
41
- </ HeaderSet >
42
- < HeaderSet id = "tools" >
43
- < SegmentedButtonSet >
44
- < ToolsMenuButton />
45
- </ SegmentedButtonSet >
46
- </ HeaderSet >
47
- < HeaderSet id = "config" >
48
- < SegmentedButtonSet >
49
- < ConfigMenuButton />
50
- </ SegmentedButtonSet >
51
- </ HeaderSet >
52
- < HeaderSet id = "help" >
53
- < SegmentedButtonSet >
54
- < HelpButton />
55
- </ SegmentedButtonSet >
56
- </ HeaderSet >
57
- </ div >
58
- ) ;
27
+ const Header : React . FC = ( ) => {
28
+ const menuContainer = useRef < HTMLDivElement | null > ( null ) ;
59
29
60
- interface HeaderSetProps {
61
- children : React . ReactNode ;
62
- id : string ;
63
- }
30
+ return (
31
+ < >
32
+ < div data-test-id = "header" className = { styles . container } >
33
+ < div className = { styles . left } >
34
+ < ButtonSet >
35
+ < ExecuteButton />
36
+ < BuildMenuButton menuContainer = { menuContainer } />
37
+ </ ButtonSet >
38
+
39
+ < ButtonSet >
40
+ < ModeMenuButton menuContainer = { menuContainer } />
41
+ < Rule />
42
+ < ChannelMenuButton menuContainer = { menuContainer } />
43
+ < Rule />
44
+ < AdvancedOptionsMenuButton menuContainer = { menuContainer } />
45
+ </ ButtonSet >
46
+ </ div >
47
+
48
+ < div className = { styles . right } >
49
+ < ButtonSet >
50
+ < ShareButton />
51
+ </ ButtonSet >
52
+
53
+ < ButtonSet >
54
+ < ToolsMenuButton menuContainer = { menuContainer } />
55
+ </ ButtonSet >
56
+
57
+ < ButtonSet >
58
+ < ConfigMenuButton menuContainer = { menuContainer } />
59
+ </ ButtonSet >
60
+
61
+ < ButtonSet >
62
+ < HelpButton />
63
+ </ ButtonSet >
64
+ </ div >
65
+ </ div >
66
+
67
+ < div ref = { menuContainer } />
68
+ </ >
69
+ ) ;
70
+ } ;
64
71
65
- const HeaderSet : React . FC < HeaderSetProps > = ( { id , children } ) => (
66
- < div className = { id == 'channel-mode' ? styles . setChannelMode : styles . set } > { children } </ div >
67
- ) ;
72
+ interface PortalProps {
73
+ menuContainer : RefObject < HTMLDivElement > ;
74
+ }
68
75
69
76
const ExecuteButton : React . FC = ( ) => {
70
77
const executionLabel = useSelector ( selectors . getExecutionLabel ) ;
@@ -73,102 +80,124 @@ const ExecuteButton: React.FC = () => {
73
80
const execute = useCallback ( ( ) => dispatch ( actions . performPrimaryAction ( ) ) , [ dispatch ] ) ;
74
81
75
82
return (
76
- < SegmentedButton isBuild onClick = { execute } >
77
- < HeaderButton bold rightIcon = { < BuildIcon /> } >
78
- { executionLabel }
79
- </ HeaderButton >
80
- </ SegmentedButton >
83
+ < OneButton isPrimary type = "button" onClick = { execute } iconRight = { BuildIcon } >
84
+ { executionLabel }
85
+ </ OneButton >
81
86
) ;
82
87
} ;
83
88
84
- const BuildMenuButton : React . FC = ( ) => {
85
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
86
- < SegmentedButton title = "Select what to build" ref = { ref } onClick = { toggle } >
87
- < HeaderButton icon = { < MoreOptionsIcon /> } />
88
- </ SegmentedButton >
89
+ const BuildMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
90
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
91
+ < IconButton type = "button" title = "Select what to build" ref = { ref } onClick = { toggle } >
92
+ < MoreOptionsIcon />
93
+ </ IconButton >
89
94
) ) ;
90
95
Button . displayName = 'BuildMenuButton.Button' ;
91
96
92
- return < PopButton Button = { Button } Menu = { BuildMenu } /> ;
97
+ return < PopButton Button = { Button } Menu = { BuildMenu } menuContainer = { menuContainer } /> ;
93
98
} ;
94
99
95
- const ModeMenuButton : React . FC = ( ) => {
100
+ const ModeMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
96
101
const label = useSelector ( selectors . getModeLabel ) ;
97
102
98
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
99
- < SegmentedButton title = "Mode — Choose the optimization level" ref = { ref } onClick = { toggle } >
100
- < HeaderButton isExpandable > { label } </ HeaderButton >
101
- </ SegmentedButton >
103
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
104
+ < OneButton
105
+ type = "button"
106
+ title = "Mode — Choose the optimization level"
107
+ ref = { ref }
108
+ onClick = { toggle }
109
+ iconRight = { ExpandableIcon }
110
+ >
111
+ { label }
112
+ </ OneButton >
102
113
) ) ;
103
114
Button . displayName = 'ModeMenuButton.Button' ;
104
115
105
- return < PopButton Button = { Button } Menu = { ModeMenu } /> ;
116
+ return < PopButton Button = { Button } Menu = { ModeMenu } menuContainer = { menuContainer } /> ;
106
117
} ;
107
118
108
- const ChannelMenuButton : React . FC = ( ) => {
119
+ const ChannelMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
109
120
const label = useSelector ( selectors . getChannelLabel ) ;
110
121
111
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
112
- < SegmentedButton title = "Channel — Choose the Rust version" ref = { ref } onClick = { toggle } >
113
- < HeaderButton isExpandable > { label } </ HeaderButton >
114
- </ SegmentedButton >
122
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
123
+ < OneButton
124
+ type = "button"
125
+ title = "Channel — Choose the Rust version"
126
+ ref = { ref }
127
+ onClick = { toggle }
128
+ iconRight = { ExpandableIcon }
129
+ >
130
+ { label }
131
+ </ OneButton >
115
132
) ) ;
116
133
Button . displayName = 'ChannelMenuButton.Button' ;
117
134
118
- return < PopButton Button = { Button } Menu = { ChannelMenu } /> ;
119
- }
135
+ return < PopButton Button = { Button } Menu = { ChannelMenu } menuContainer = { menuContainer } /> ;
136
+ } ;
120
137
121
- const AdvancedOptionsMenuButton : React . FC = ( ) => {
138
+ const AdvancedOptionsMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
122
139
const advancedOptionsSet = useSelector ( selectors . getAdvancedOptionsSet ) ;
123
140
124
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
125
- < SegmentedButton title = "Advanced compilation flags" ref = { ref } onClick = { toggle } >
126
- < HeaderButton icon = { advancedOptionsSet ? < MoreOptionsActiveIcon /> : < MoreOptionsIcon /> } />
127
- </ SegmentedButton >
141
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
142
+ < IconButton type = "button" title = "Advanced compilation flags" ref = { ref } onClick = { toggle } >
143
+ { advancedOptionsSet ? < MoreOptionsActiveIcon /> : < MoreOptionsIcon /> }
144
+ </ IconButton >
128
145
) ) ;
129
146
Button . displayName = 'AdvancedOptionsMenuButton.Button' ;
130
147
131
- return < PopButton Button = { Button } Menu = { AdvancedOptionsMenu } /> ;
132
- }
148
+ return < PopButton Button = { Button } Menu = { AdvancedOptionsMenu } menuContainer = { menuContainer } /> ;
149
+ } ;
133
150
134
151
const ShareButton : React . FC = ( ) => {
135
152
const dispatch = useAppDispatch ( ) ;
136
153
const gistSave = useCallback ( ( ) => dispatch ( performGistSave ( ) ) , [ dispatch ] ) ;
137
154
138
155
return (
139
- < SegmentedButton title = "Create shareable links to this code" onClick = { gistSave } >
140
- < HeaderButton > Share</ HeaderButton >
141
- </ SegmentedButton >
156
+ < OneButton type = "button" title = "Create shareable links to this code" onClick = { gistSave } >
157
+ Share
158
+ </ OneButton >
142
159
) ;
143
160
} ;
144
161
145
-
146
- const ToolsMenuButton : React . FC = ( ) => {
147
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
148
- < SegmentedButton title = "Run extra tools on the source code" ref = { ref } onClick = { toggle } >
149
- < HeaderButton isExpandable > Tools</ HeaderButton >
150
- </ SegmentedButton >
162
+ const ToolsMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
163
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
164
+ < OneButton
165
+ type = "button"
166
+ title = "Run extra tools on the source code"
167
+ ref = { ref }
168
+ onClick = { toggle }
169
+ iconRight = { ExpandableIcon }
170
+ >
171
+ Tools
172
+ </ OneButton >
151
173
) ) ;
152
174
Button . displayName = 'ToolsMenuButton.Button' ;
153
175
154
- return < PopButton Button = { Button } Menu = { ToolsMenu } /> ;
176
+ return < PopButton Button = { Button } Menu = { ToolsMenu } menuContainer = { menuContainer } /> ;
155
177
} ;
156
178
157
- const ConfigMenuButton : React . FC = ( ) => {
158
- const Button = React . forwardRef < HTMLButtonElement , { toggle : ( ) => void } > ( ( { toggle } , ref ) => (
159
- < SegmentedButton title = "Show the configuration options" ref = { ref } onClick = { toggle } >
160
- < HeaderButton icon = { < ConfigIcon /> } isExpandable > Config</ HeaderButton >
161
- </ SegmentedButton >
179
+ const ConfigMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
180
+ const Button = React . forwardRef < HTMLButtonElement , ButtonProps > ( ( { toggle } , ref ) => (
181
+ < OneButton
182
+ type = "button"
183
+ title = "Show the configuration options"
184
+ ref = { ref }
185
+ onClick = { toggle }
186
+ iconLeft = { ConfigIcon }
187
+ iconRight = { ExpandableIcon }
188
+ >
189
+ Config
190
+ </ OneButton >
162
191
) ) ;
163
192
Button . displayName = 'ConfigMenuButton.Button' ;
164
193
165
- return < PopButton Button = { Button } Menu = { ConfigMenu } /> ;
194
+ return < PopButton Button = { Button } Menu = { ConfigMenu } menuContainer = { menuContainer } /> ;
166
195
} ;
167
196
168
197
const HelpButton : React . FC = ( ) => (
169
- < SegmentedLink title = "View help" action = { actions . navigateToHelp } >
170
- < HeaderButton icon = { < HelpIcon /> } />
171
- </ SegmentedLink >
198
+ < IconLink title = "View help" action = { actions . navigateToHelp } >
199
+ < HelpIcon />
200
+ </ IconLink >
172
201
) ;
173
202
174
203
export default Header ;
0 commit comments