All files / navigation index.js

65.22% Statements 15/23
50% Branches 4/8
50% Functions 3/6
61.9% Lines 13/21
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150                1x 1x 1x 1x         6x                                                                                                                                                                 1x 1x 1x   2x       1x           1x 1x                 2x                                                        
 
/**
 * Spec
 * http://www.google.com/design/spec/patterns/navigation-drawer.html#
 * http://www.google.com/design/spec/patterns/app-structure.html#app-structure-top-level-navigation-strategies
 * http://www.google.com/design/spec/layout/structure.html#structure-side-nav
 */
 
import React from 'react'
import {Link, withRouter} from 'react-router'
import classnames from 'classnames'
import Icon from '../icon/'
 
/**
 * Navigation item
 */
const Item = ({index, onClick, item}) => (
  <li key={index} className='Navigation-item' onClick={onClick}>
    <Link
      activeClassName='active'
      to={item.link}
      className='Navigation-link'
      title={item.text}
    >
      {item.text}
    </Link>
    {item.links &&
      <ul className='Navigation'>
        {item.links.map((item, index) =>
          <Item
            key={index}
            onClick={onClick}
            item={item}
          />
        )}
      </ul>
    }
  </li>
)
 
/**
 * Navigation
 */
class Navigation extends React.Component {
 
  /**
   * Property types
   */
  static propTypes = {
    links: React.PropTypes.array.isRequired,
    onChange: React.PropTypes.func
  }
 
  /**
   * Default properties
   */
  static defaultProps = {
    onChange: () => {}
  }
 
  /**
   * State
   */
  state = {
    visible: false
  }
 
  /**
   * Handle click on navigation link
   */
  onClick = (index) => {
    const item = this.props.links[index]
    this.props.onChange(item)
    this.close()
  }
 
  /**
   * Hide overlay
   */
  close = () => {
    this.setState({
      visible: false
    })
  }
 
  /**
   * Open overlay
   */
  open = () => {
    this.setState({
      visible: true
    })
  }
 
  /**
   * Update parent component on initial render
   */
  componentDidMount () {
    let activeRouteIndex = 0
    this.props.links.forEach((link, index) => {
      // check for this props router as it is undefined in tests
      Iif (this.props.router && this.props.router.isActive(link.link)) {
        activeRouteIndex = index
      }
    })
    this.props.onChange(this.props.links[activeRouteIndex])
  }
 
  /**
   * Render component
   */
  render () {
    return (
      <div>
        <nav className={this.state.visible ? 'is-visible' : ''}>
          <div className='Navigation-logo'>
            <a href='#' onClick={this.close}>
              <Icon.Logo fill='#A7A5A5' />
            </a>
          </div>
          <ul className='Navigation'>
            {this.props.links.map((item, index) =>
              <Item
                key={index}
                onClick={() => this.onClick(index)}
                item={item}
              />
            )}
          </ul>
        </nav>
        <div className='Navigation-hamburger'>
          <Icon.Button onClick={this.open}>
            <Icon.Menu />
          </Icon.Button>
        </div>
        <div
          className={classnames('Navigation-overlay', {
            'is-visible': this.state.visible
          })}
          onClick={this.close}
          onTouchEnd={this.close}
        />
      </div>
    )
  }
 
}
 
export default withRouter(Navigation)