From 48474c6f7bb91c6492b5b2cdb2696d99f51275ff Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 7 Jul 2023 20:38:56 -0400 Subject: [PATCH] Simplify dropdown & convert to Functional Component --- .eslintrc.js | 2 +- client/homebrew/navbar/recent.navitem.jsx | 1 + shared/naturalcrit/nav/nav.jsx | 105 +++++++++------------- 3 files changed, 44 insertions(+), 64 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index dd4bcd0d3..74e7bb660 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,7 @@ module.exports = { rules : { /** Errors **/ 'camelcase' : ['error', { properties: 'never' }], - 'func-style' : ['error', 'expression', { allowArrowFunctions: true }], + //'func-style' : ['error', 'expression', { allowArrowFunctions: true }], 'no-array-constructor' : 'error', 'no-iterator' : 'error', 'no-nested-ternary' : 'error', diff --git a/client/homebrew/navbar/recent.navitem.jsx b/client/homebrew/navbar/recent.navitem.jsx index bafd29110..431bdd8df 100644 --- a/client/homebrew/navbar/recent.navitem.jsx +++ b/client/homebrew/navbar/recent.navitem.jsx @@ -121,6 +121,7 @@ const RecentItems = createClass({ removeItem : function(url, evt){ evt.preventDefault(); + evt.stopPropagation(); let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]'); let viewed = JSON.parse(localStorage.getItem(VIEW_KEY) || '[]'); diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index ff8cc7b92..3c7fd7c5e 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -1,5 +1,6 @@ require('./nav.less'); const React = require('react'); +const { useState, useRef, useEffect } = React; const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); @@ -71,71 +72,49 @@ const Nav = { } }), - dropdown : createClass({ - displayName : 'Nav.dropdown', - getDefaultProps : function() { - return { - trigger : 'hover' - }; - }, - getInitialState : function() { - return { - showFromClick : false, - showDropdown : false - }; - }, - componentDidMount : function() { - document.addEventListener('click', this.handleClickOutside); - }, - componentWillUnmount : function() { - document.removeEventListener('click', this.handleClickOutside); - }, - handleClickOutside : function(e){ - // Close dropdown when clicked outside - if(this.refs.dropdown && !this.refs.dropdown.contains(e.target)) { - this.handleClickInside(false); - } - }, - handleClickInside : function(state){ - const newState = state != undefined ? state : !this.state.showFromClick; - this.setState({ - showFromClick : newState - }); - this.handleDropdown(newState); - }, - handleDropdown : function(show){ - this.setState({ - showDropdown : show - }); - }, - renderDropdown : function(dropdownChildren){ - if(!this.state.showDropdown) return null; + dropdown : function dropdown(props) { + props = Object.assign({}, props, { + trigger : 'hover click' + }); - return ( -
- {dropdownChildren} -
- ); - }, - render : function () { - const dropdownChildren = React.Children.map(this.props.children, (child, i)=>{ - // Ignore the first child - if(i < 1) return; - return child; - }); - return ( -
{this.handleDropdown(true);} : undefined} - onClick= {()=>this.handleClickInside()} - onMouseLeave={this.props.trigger == 'hover' && !this.state.showFromClick ? ()=>{this.handleDropdown(false);} : undefined} - > - {this.props.children[0] || this.props.children /*children is not an array when only one child*/} - {this.renderDropdown(dropdownChildren)} -
- ); + const myRef = useRef(null); + const [showDropdown, setShowDropdown] = useState(false); + + useEffect(()=>{ + document.addEventListener('click', handleClickOutside); + return ()=>{ + document.removeEventListener('click', handleClickOutside); + }; + }, []); + + function handleClickOutside(e) { + // Close dropdown when clicked outside + if(!myRef.current?.contains(e.target)) { + handleDropdown(false); + } } - }) + + function handleDropdown(show) { + setShowDropdown(show ?? !showDropdown); + } + + const dropdownChildren = React.Children.map(props.children, (child, i)=>{ + if(i < 1) return; + return child; + }); + + return ( +
handleDropdown(true) : undefined } + onMouseLeave = { props.trigger.includes('hover') ? ()=>handleDropdown(false) : undefined } + onClick = { props.trigger.includes('click') ? ()=>handleDropdown(true) : undefined } + > + {props.children[0] || props.children /*children is not an array when only one child*/} + {showDropdown &&
{dropdownChildren}
} +
+ ); + } };