refactor(client): Refactor menu to use refs (#37047)

* Refactor menu to use refs #37025

* Fix Header tests #37025

* Removing unneeded forwardRefs #37025
This commit is contained in:
Ismael González Trujillo
2019-10-07 13:33:47 +01:00
committed by Ahmad Abdolsaheb
parent d0cda5820c
commit a68345ae56
5 changed files with 52 additions and 51 deletions

View File

@ -41,5 +41,6 @@ describe('<NavLinks />', () => {
const UniversalNavProps = { const UniversalNavProps = {
displayMenu: false, displayMenu: false,
menuButtonRef: {}, menuButtonRef: {},
searchBarRef: {},
toggleDisplayMenu: function() {} toggleDisplayMenu: function() {}
}; };

View File

@ -1,25 +1,24 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const MenuButton = React.forwardRef((props, ref) => { const MenuButton = props => (
return (
<button <button
aria-expanded={props.displayMenu} aria-expanded={props.displayMenu}
className={ className={
'toggle-button-nav' + (props.displayMenu ? ' reverse-toggle-color' : '') 'toggle-button-nav' + (props.displayMenu ? ' reverse-toggle-color' : '')
} }
onClick={props.onClick} onClick={props.onClick}
ref={ref} ref={props.innerRef}
> >
Menu Menu
</button> </button>
); );
});
MenuButton.displayName = 'MenuButton'; MenuButton.displayName = 'MenuButton';
MenuButton.propTypes = { MenuButton.propTypes = {
className: PropTypes.string, className: PropTypes.string,
displayMenu: PropTypes.bool.isRequired, displayMenu: PropTypes.bool.isRequired,
innerRef: PropTypes.object,
onClick: PropTypes.func.isRequired onClick: PropTypes.func.isRequired
}; };

View File

@ -8,18 +8,20 @@ import MenuButton from './MenuButton';
import NavLinks from './NavLinks'; import NavLinks from './NavLinks';
import './universalNav.css'; import './universalNav.css';
export const UniversalNav = React.forwardRef( export const UniversalNav = ({
({ displayMenu, toggleDisplayMenu }, ref) => ( displayMenu,
toggleDisplayMenu,
menuButtonRef,
searchBarRef
}) => (
<nav <nav
className={ className={'universal-nav nav-padding' + (displayMenu ? ' expand-nav' : '')}
'universal-nav nav-padding' + (displayMenu ? ' expand-nav' : '')
}
id='universal-nav' id='universal-nav'
> >
<div <div
className={'universal-nav-left' + (displayMenu ? ' display-flex' : '')} className={'universal-nav-left' + (displayMenu ? ' display-flex' : '')}
> >
<SearchBar /> <SearchBar innerRef={searchBarRef} />
</div> </div>
<div className='universal-nav-middle'> <div className='universal-nav-middle'>
<Link id='universal-nav-logo' to='/'> <Link id='universal-nav-logo' to='/'>
@ -31,11 +33,10 @@ export const UniversalNav = React.forwardRef(
</div> </div>
<MenuButton <MenuButton
displayMenu={displayMenu} displayMenu={displayMenu}
innerRef={menuButtonRef}
onClick={toggleDisplayMenu} onClick={toggleDisplayMenu}
ref={ref}
/> />
</nav> </nav>
)
); );
UniversalNav.displayName = 'UniversalNav'; UniversalNav.displayName = 'UniversalNav';
@ -44,5 +45,6 @@ export default UniversalNav;
UniversalNav.propTypes = { UniversalNav.propTypes = {
displayMenu: PropTypes.bool, displayMenu: PropTypes.bool,
menuButtonRef: PropTypes.object, menuButtonRef: PropTypes.object,
searchBarRef: PropTypes.object,
toggleDisplayMenu: PropTypes.func toggleDisplayMenu: PropTypes.func
}; };

View File

@ -12,6 +12,7 @@ export class Header extends React.Component {
displayMenu: false displayMenu: false
}; };
this.menuButtonRef = React.createRef(); this.menuButtonRef = React.createRef();
this.searchBarRef = React.createRef();
this.handleClickOutside = this.handleClickOutside.bind(this); this.handleClickOutside = this.handleClickOutside.bind(this);
this.toggleDisplayMenu = this.toggleDisplayMenu.bind(this); this.toggleDisplayMenu = this.toggleDisplayMenu.bind(this);
} }
@ -29,7 +30,8 @@ export class Header extends React.Component {
this.state.displayMenu && this.state.displayMenu &&
this.menuButtonRef.current && this.menuButtonRef.current &&
!this.menuButtonRef.current.contains(event.target) && !this.menuButtonRef.current.contains(event.target) &&
event.target.id !== 'fcc_instantsearch' this.searchBarRef.current &&
!this.searchBarRef.current.contains(event.target)
) { ) {
this.toggleDisplayMenu(); this.toggleDisplayMenu();
} }
@ -48,7 +50,8 @@ export class Header extends React.Component {
<header> <header>
<UniversalNav <UniversalNav
displayMenu={displayMenu} displayMenu={displayMenu}
ref={this.menuButtonRef} menuButtonRef={this.menuButtonRef}
searchBarRef={this.searchBarRef}
toggleDisplayMenu={this.toggleDisplayMenu} toggleDisplayMenu={this.toggleDisplayMenu}
/> />
</header> </header>

View File

@ -23,6 +23,7 @@ import './searchbar.css';
configure({ ignoreTags: ['select', 'textarea'] }); configure({ ignoreTags: ['select', 'textarea'] });
const propTypes = { const propTypes = {
innerRef: PropTypes.object,
isDropdownEnabled: PropTypes.bool, isDropdownEnabled: PropTypes.bool,
isSearchFocused: PropTypes.bool, isSearchFocused: PropTypes.bool,
toggleSearchDropdown: PropTypes.func.isRequired, toggleSearchDropdown: PropTypes.func.isRequired,
@ -51,7 +52,6 @@ class SearchBar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.searchBarRef = React.createRef();
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleSearch = this.handleSearch.bind(this); this.handleSearch = this.handleSearch.bind(this);
this.handleMouseEnter = this.handleMouseEnter.bind(this); this.handleMouseEnter = this.handleMouseEnter.bind(this);
@ -87,7 +87,7 @@ class SearchBar extends Component {
handleFocus(e) { handleFocus(e) {
const { toggleSearchFocused } = this.props; const { toggleSearchFocused } = this.props;
const isSearchFocused = this.searchBarRef.current.contains(e.target); const isSearchFocused = this.props.innerRef.current.contains(e.target);
if (!isSearchFocused) { if (!isSearchFocused) {
// Reset if user clicks outside of // Reset if user clicks outside of
// search bar / closes dropdown // search bar / closes dropdown
@ -177,15 +177,11 @@ class SearchBar extends Component {
}; };
render() { render() {
const { isDropdownEnabled, isSearchFocused } = this.props; const { isDropdownEnabled, isSearchFocused, innerRef } = this.props;
const { index } = this.state; const { index } = this.state;
return ( return (
<div <div className='fcc_searchBar' data-testid='fcc_searchBar' ref={innerRef}>
className='fcc_searchBar'
data-testid='fcc_searchBar'
ref={this.searchBarRef}
>
<HotKeys handlers={this.keyHandlers} keyMap={this.keyMap}> <HotKeys handlers={this.keyHandlers} keyMap={this.keyMap}>
<div className='fcc_search_wrapper'> <div className='fcc_search_wrapper'>
<label className='fcc_sr_only' htmlFor='fcc_instantsearch'> <label className='fcc_sr_only' htmlFor='fcc_instantsearch'>