1- import React , { Fragment } from "react"
1+ import React , { useState , useEffect } from "react"
22import PropTypes from "prop-types"
33import classNames from "classnames"
44import throttle from "lodash/throttle"
55import { NavLink } from "react-router-dom"
66import Menu from "react-feather/dist/icons/menu"
77import ChevronRight from "react-feather/dist/icons/chevron-right"
8- import { Accordions } from "undernet"
98
9+ import { Accordions } from "undernet"
1010import "./styles.scss"
1111
1212const pkg = require ( "projectRoot/package.json" )
1313const MENU_COLLAPSE_WIDTH = 1199
1414
15- export default class SideNav extends React . Component {
16- constructor ( props ) {
17- super ( props )
18- this . handleMenuVisibility = throttle ( this . handleMenuVisibility , 50 )
19-
20- this . state = {
21- menuIsOpen : window . innerWidth > MENU_COLLAPSE_WIDTH ,
22- }
15+ export default function SideNav ( props ) {
16+ const getWindowInnerWidth = ( ) => {
17+ return window . innerWidth
2318 }
2419
25- static propTypes = {
26- navItems : PropTypes . arrayOf (
27- PropTypes . shape ( {
28- header : PropTypes . string ,
29- links : PropTypes . arrayOf (
30- PropTypes . shape ( {
31- name : PropTypes . string ,
32- url : PropTypes . string ,
33- } )
34- ) ,
35- } )
36- ) . isRequired ,
37- navListClasses : PropTypes . string ,
38- }
20+ const [ menuIsOpen , setMenuIsOpen ] = useState ( getWindowInnerWidth ( ) > MENU_COLLAPSE_WIDTH )
3921
40- componentDidMount ( ) {
41- window . addEventListener ( "resize" , this . handleMenuVisibility )
22+ let handleMenuVisibility = ( ) => {
23+ if ( getWindowInnerWidth ( ) > MENU_COLLAPSE_WIDTH ) {
24+ setMenuIsOpen ( true )
25+ }
26+ }
4227
43- const menuIsOpen = window . innerWidth > MENU_COLLAPSE_WIDTH
44- this . setState ( { menuIsOpen } )
28+ handleMenuVisibility = throttle ( handleMenuVisibility , 50 )
4529
30+ useEffect ( ( ) => {
4631 Accordions . start ( )
47- }
48-
49- componentWillUnmount ( ) {
50- window . removeEventListener ( "resize" , this . handleMenuVisibility )
51- Accordions . stop ( )
52- }
32+ window . addEventListener ( "resize" , handleMenuVisibility )
33+ setMenuIsOpen ( getWindowInnerWidth ( ) > MENU_COLLAPSE_WIDTH )
5334
54- componentDidUpdate ( _ , prevState ) {
55- if ( prevState . menuIsOpen !== this . state . menuIsOpen ) {
35+ return ( ) => {
36+ window . removeEventListener ( "resize" , handleMenuVisibility )
5637 Accordions . stop ( )
57- Accordions . start ( )
5838 }
59- }
39+ } , [ ] )
6040
61- handleCollapseClick = ( ) => {
62- if ( window . innerWidth <= MENU_COLLAPSE_WIDTH ) {
63- this . setState ( { menuIsOpen : false } )
64- }
65- }
41+ useEffect ( ( ) => {
42+ Accordions . stop ( )
43+ Accordions . start ( )
44+ } , [ menuIsOpen ] )
45+
46+ // handlers
6647
67- handleMenuVisibility = ( ) => {
68- if ( window . innerWidth > MENU_COLLAPSE_WIDTH ) {
69- this . setState ( { menuIsOpen : true } )
48+ const handleCollapseClick = ( ) => {
49+ if ( getWindowInnerWidth ( ) <= MENU_COLLAPSE_WIDTH ) {
50+ setMenuIsOpen ( false )
7051 }
7152 }
7253
73- handleMenuToggleClick = event => {
54+ const handleMenuToggleClick = event => {
7455 event . preventDefault ( )
75- this . setState ( { menuIsOpen : ! this . state . menuIsOpen } )
56+ setMenuIsOpen ( ! menuIsOpen )
7657 }
7758
78- get buttonClasses ( ) {
59+ const buttonClasses = ( ) => {
7960 return classNames ( "is-justified-center is-aligned-center is-flex is-hidden-xlarge" , {
80- "rotate-180" : ! this . state . menuIsOpen ,
61+ "rotate-180" : ! menuIsOpen ,
8162 } )
8263 }
8364
84- get menuClasses ( ) {
65+ const menuClasses = ( ) => {
8566 return classNames ( "row side-nav-menu accordion has-padding-3" , {
86- "is-hidden" : ! this . state . menuIsOpen ,
67+ "is-hidden" : ! menuIsOpen ,
8768 } )
8869 }
8970
90- accordionIsActive ( items ) {
71+ const accordionIsActive = items => {
9172 let isActive = false
9273
9374 items . forEach ( item => {
@@ -99,14 +80,14 @@ export default class SideNav extends React.Component {
9980 return isActive
10081 }
10182
102- renderAccordionChildLink = item => {
83+ const renderAccordionChildLink = item => {
10384 return (
10485 < li key = { item . name } role = "none" >
10586 < NavLink
10687 role = "listitem"
10788 className = "side-nav-link-item has-black-text is-flex is-aligned-center"
10889 activeClassName = "active"
109- onClick = { this . handleCollapseClick }
90+ onClick = { handleCollapseClick }
11091 to = { item . url }
11192 >
11293 { item . name } < ChevronRight size = { 16 } role = "presentation" focusable = "false" />
@@ -115,11 +96,11 @@ export default class SideNav extends React.Component {
11596 )
11697 }
11798
118- renderAccordionRow ( section , index ) {
119- const listItems = section . links . map ( this . renderAccordionChildLink )
99+ const renderAccordionRow = ( section , index ) => {
100+ const listItems = section . links . map ( renderAccordionChildLink )
120101
121102 return (
122- < Fragment key = { section . header } >
103+ < React . Fragment key = { section . header } >
123104 < h4 className = "paragraph" >
124105 < button
125106 id = { `nav-acc-button${ index } ` }
@@ -133,53 +114,62 @@ export default class SideNav extends React.Component {
133114 < ul className = "accordion-content" id = { `nav-acc-content${ index } ` } >
134115 { listItems }
135116 </ ul >
136- </ Fragment >
117+ </ React . Fragment >
137118 )
138119 }
139120
140- renderNavAccordion ( ) {
141- return this . props . navItems . map ( ( section , i ) => {
121+ const renderNavAccordion = ( ) => {
122+ return props . navItems . map ( ( section , i ) => {
142123 return (
143124 < div
144- data-visible = { this . accordionIsActive ( section . links ) ? "true" : "false" }
125+ data-visible = { accordionIsActive ( section . links ) ? "true" : "false" }
145126 data-accordion-row = { `nav-acc-content${ i } ` }
146- className = { classNames ( "accordion-row" , this . props . navListClasses ) }
127+ className = { classNames ( "accordion-row" , props . navListClasses ) }
147128 key = { section . links [ 0 ] . url }
148129 >
149- { this . renderAccordionRow ( section , i ) }
130+ { renderAccordionRow ( section , i ) }
150131 </ div >
151132 )
152133 } )
153134 }
154135
155- render ( ) {
156- return (
157- < div className = "xsmall-12 xlarge-2 columns has-no-padding" id = "side-nav" >
158- < div className = "fluid grid side-nav-wrapper" >
159- < div className = "row is-flex is-hidden-xlarge side-nav-expand" >
160- < button
161- onClick = { this . handleMenuToggleClick }
162- className = { this . buttonClasses }
163- aria-controls = "side-nav-wrapper"
164- aria-expanded = { this . state . menuIsOpen }
165- >
166- < Menu size = { 20 } role = "presentation" focusable = "false" /> { " " }
167- < span className = "has-black-text" > Explore</ span >
168- </ button >
169- </ div >
170-
171- < nav
172- data-accordion = "side-nav-accordion"
173- className = { this . menuClasses }
174- id = "side-nav-wrapper"
136+ return (
137+ < div className = "xsmall-12 xlarge-2 columns has-no-padding" id = "side-nav" >
138+ < div className = "fluid grid side-nav-wrapper" >
139+ < div className = "row is-flex is-hidden-xlarge side-nav-expand" >
140+ < button
141+ onClick = { handleMenuToggleClick }
142+ className = { buttonClasses ( ) }
143+ aria-controls = "side-nav-wrapper"
144+ aria-expanded = { menuIsOpen }
175145 >
176- < p className = "version-text has-no-padding has-gray800-text xsmall-12 columns" >
177- Version { pkg . version }
178- </ p >
179- { this . renderNavAccordion ( ) }
180- </ nav >
146+ < Menu size = { 20 } role = "presentation" focusable = "false" /> { " " }
147+ < span className = "has-black-text" > Explore</ span >
148+ </ button >
181149 </ div >
150+
151+ < nav data-accordion = "side-nav-accordion" className = { menuClasses ( ) } id = "side-nav-wrapper" >
152+ < p className = "version-text has-no-padding has-gray800-text xsmall-12 columns" >
153+ Version { pkg . version }
154+ </ p >
155+ { renderNavAccordion ( ) }
156+ </ nav >
182157 </ div >
183- )
184- }
158+ </ div >
159+ )
160+ }
161+
162+ SideNav . propTypes = {
163+ navItems : PropTypes . arrayOf (
164+ PropTypes . shape ( {
165+ header : PropTypes . string ,
166+ links : PropTypes . arrayOf (
167+ PropTypes . shape ( {
168+ name : PropTypes . string ,
169+ url : PropTypes . string ,
170+ } )
171+ ) ,
172+ } )
173+ ) . isRequired ,
174+ navListClasses : PropTypes . string ,
185175}
0 commit comments