1- import React , { useCallback } from 'react' ;
1+ import React , { RefObject , useCallback , useRef } from 'react' ;
22import { useSelector } from 'react-redux' ;
33
44import AdvancedOptionsMenu from './AdvancedOptionsMenu' ;
55import BuildMenu from './BuildMenu' ;
6+ import { ButtonSet , IconButton , IconLink , Button as OneButton , Rule } from './ButtonSet' ;
67import ChannelMenu from './ChannelMenu' ;
78import 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' ;
1017import ModeMenu from './ModeMenu' ;
11- import PopButton from './PopButton' ;
12- import { SegmentedButton , SegmentedButtonSet , SegmentedLink } from './SegmentedButton' ;
18+ import PopButton , { ButtonProps } from './PopButton' ;
1319import ToolsMenu from './ToolsMenu' ;
14-
1520import * as actions from './actions' ;
16- import * as selectors from './selectors' ;
1721import { useAppDispatch } from './configureStore' ;
1822import { performGistSave } from './reducers/output/gist' ;
23+ import * as selectors from './selectors' ;
1924
2025import styles from './Header.module.css' ;
2126
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 ) ;
5929
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+ } ;
6471
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+ }
6875
6976const ExecuteButton : React . FC = ( ) => {
7077 const executionLabel = useSelector ( selectors . getExecutionLabel ) ;
@@ -73,102 +80,124 @@ const ExecuteButton: React.FC = () => {
7380 const execute = useCallback ( ( ) => dispatch ( actions . performPrimaryAction ( ) ) , [ dispatch ] ) ;
7481
7582 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 >
8186 ) ;
8287} ;
8388
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 >
8994 ) ) ;
9095 Button . displayName = 'BuildMenuButton.Button' ;
9196
92- return < PopButton Button = { Button } Menu = { BuildMenu } /> ;
97+ return < PopButton Button = { Button } Menu = { BuildMenu } menuContainer = { menuContainer } /> ;
9398} ;
9499
95- const ModeMenuButton : React . FC = ( ) => {
100+ const ModeMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
96101 const label = useSelector ( selectors . getModeLabel ) ;
97102
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 >
102113 ) ) ;
103114 Button . displayName = 'ModeMenuButton.Button' ;
104115
105- return < PopButton Button = { Button } Menu = { ModeMenu } /> ;
116+ return < PopButton Button = { Button } Menu = { ModeMenu } menuContainer = { menuContainer } /> ;
106117} ;
107118
108- const ChannelMenuButton : React . FC = ( ) => {
119+ const ChannelMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
109120 const label = useSelector ( selectors . getChannelLabel ) ;
110121
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 >
115132 ) ) ;
116133 Button . displayName = 'ChannelMenuButton.Button' ;
117134
118- return < PopButton Button = { Button } Menu = { ChannelMenu } /> ;
119- }
135+ return < PopButton Button = { Button } Menu = { ChannelMenu } menuContainer = { menuContainer } /> ;
136+ } ;
120137
121- const AdvancedOptionsMenuButton : React . FC = ( ) => {
138+ const AdvancedOptionsMenuButton : React . FC < PortalProps > = ( { menuContainer } ) => {
122139 const advancedOptionsSet = useSelector ( selectors . getAdvancedOptionsSet ) ;
123140
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 >
128145 ) ) ;
129146 Button . displayName = 'AdvancedOptionsMenuButton.Button' ;
130147
131- return < PopButton Button = { Button } Menu = { AdvancedOptionsMenu } /> ;
132- }
148+ return < PopButton Button = { Button } Menu = { AdvancedOptionsMenu } menuContainer = { menuContainer } /> ;
149+ } ;
133150
134151const ShareButton : React . FC = ( ) => {
135152 const dispatch = useAppDispatch ( ) ;
136153 const gistSave = useCallback ( ( ) => dispatch ( performGistSave ( ) ) , [ dispatch ] ) ;
137154
138155 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 >
142159 ) ;
143160} ;
144161
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 >
151173 ) ) ;
152174 Button . displayName = 'ToolsMenuButton.Button' ;
153175
154- return < PopButton Button = { Button } Menu = { ToolsMenu } /> ;
176+ return < PopButton Button = { Button } Menu = { ToolsMenu } menuContainer = { menuContainer } /> ;
155177} ;
156178
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 >
162191 ) ) ;
163192 Button . displayName = 'ConfigMenuButton.Button' ;
164193
165- return < PopButton Button = { Button } Menu = { ConfigMenu } /> ;
194+ return < PopButton Button = { Button } Menu = { ConfigMenu } menuContainer = { menuContainer } /> ;
166195} ;
167196
168197const 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 >
172201) ;
173202
174203export default Header ;
0 commit comments