Skip to content

Commit de89655

Browse files
author
Brendan Abbott
committed
Decouple Navigation component
1 parent b301d3b commit de89655

File tree

8 files changed

+159
-102
lines changed

8 files changed

+159
-102
lines changed

src/components/BodySchema/BodySchema.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,15 @@ export default class BodySchema extends Component {
9696
)
9797
}
9898

99+
/**
100+
* Responsible for updating the state of all properties that
101+
* have been expanded by the user.
102+
*
103+
* @param {string} propertyName
104+
*/
99105
onClick (propertyName) {
100106
const { expandedProp } = this.state
107+
101108
if (expandedProp.includes(propertyName)) {
102109
const newExpanded = expandedProp.filter((prop) => prop !== propertyName)
103110
this.setState({ expandedProp: newExpanded })

src/components/Indicator/Indicator.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ export default class Indicator extends Component {
1111
const { status, className } = this.props
1212

1313
return (
14-
<div className={classNames('indicator', className, {
14+
<span className={classNames('indicator', className, {
1515
[`indicator--${status}`]: status
1616
})}>
17-
<img src={arrow} title='arrow' />
18-
</div>
17+
<img src={arrow} alt='' title='arrow' />
18+
</span>
1919
)
2020
}
2121
}

src/components/Navigation/Navigation.js

Lines changed: 23 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,55 @@
11
import React, { Component } from 'react'
2-
import classNames from 'classnames'
32
import PropTypes from 'prop-types'
4-
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
53

6-
import Indicator from '../Indicator/Indicator'
4+
import NavigationTag from '../NavigationTag/NavigationTag'
75

86
import './Navigation.scss'
97

108
export default class Navigation extends Component {
119
constructor (props) {
1210
super(props)
1311

12+
this.onClick = this.onClick.bind(this)
13+
1414
this.state = {
1515
expandedTags: []
1616
}
1717
}
1818

19-
componentWillMount () {
20-
this.props.navigation.map((tag) => {
21-
tag.methods.map((method) => {
22-
if (`#${method.link}` === this.props.location.hash) {
23-
this.updateExpandedTags(tag.title)
24-
}
25-
})
26-
})
27-
}
28-
2919
render () {
30-
const { navigation } = this.props
20+
const { navigation, location } = this.props
3121
const { expandedTags } = this.state
3222

3323
return (
34-
<div className='nav'>
24+
<nav className='nav'>
3525
{navigation && navigation.map((tag) => {
3626
let status
37-
if (expandedTags.indexOf(tag.title) === -1) {
27+
if (expandedTags.includes(tag.title)) {
3828
status = 'right'
3929
}
30+
4031
return (
41-
<div key={tag.title}>
42-
<a
43-
className='nav-level1'
44-
key={tag.title}
45-
href={`#${tag.title}`}
46-
onClick={this.updateExpandedTags.bind(this, tag.title)}
47-
>
48-
{tag.title}
49-
<Indicator className='property-indicator' status={status} />
50-
</a>
51-
{expandedTags.indexOf(tag.title) !== -1 &&
52-
<ReactCSSTransitionGroup
53-
transitionName='nav-slide-toggle'
54-
transitionEnterTimeout={500}
55-
transitionLeaveTimeout={500}
56-
transitionAppear
57-
transitionAppearTimeout={500}
58-
>
59-
<div>
60-
{tag.methods.map((method) => {
61-
const isActive = (`#${method.link}` === this.props.location.hash)
62-
return (
63-
<a
64-
className={classNames('nav-level2', {
65-
active: isActive
66-
})}
67-
key={method.link}
68-
href={`#${method.link}`}
69-
>
70-
<span className='method-type'>{method.type.toUpperCase()}</span>
71-
<span className='method-title'>{method.title}</span>
72-
</a>
73-
)
74-
})}
75-
</div>
76-
</ReactCSSTransitionGroup>
77-
}
78-
</div>
32+
<NavigationTag
33+
key={tag.title}
34+
title={tag.title}
35+
methods={tag.methods}
36+
status={status}
37+
onClick={this.onClick}
38+
location={location}
39+
/>
7940
)
8041
})}
81-
</div>
42+
</nav>
8243
)
8344
}
8445

85-
updateExpandedTags (tagTitle) {
46+
/**
47+
* Responsible for updating the state of the navigation with all
48+
* expanded tags.
49+
*
50+
* @param {string} tagTitle
51+
*/
52+
onClick (tagTitle) {
8653
const { expandedTags } = this.state
8754

8855
if (expandedTags.includes(tagTitle)) {

src/components/Navigation/Navigation.scss

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,8 @@
1515
.indicator {
1616
float: right;
1717
}
18-
}
19-
20-
.nav-level1 {
21-
display: block;
22-
padding: 5px 20px;
23-
margin-top: 10px;
24-
cursor: pointer;
25-
text-transform: uppercase;
26-
color: $blue;
27-
font-weight: bold;
28-
&.active {
29-
background-color: $grey-dark;
30-
}
31-
;
32-
}
3318

34-
.nav-level2 {
35-
display: flex;
36-
padding: 5px 20px;
37-
text-indent: 10px;
38-
cursor: pointer;
39-
color: black;
40-
&.active {
41-
background-color: $grey-dark;
19+
> div {
20+
padding: 10px;
4221
}
4322
}
44-
45-
.method-type {
46-
}
47-
48-
.method-title {
49-
padding-left: 5px;
50-
//border: 1px solid red;
51-
text-indent: 0;
52-
}
53-
54-
.nav-slide-toggle-appear,
55-
.nav-slide-toggle-enter {
56-
max-height: 0;
57-
}
58-
59-
.nav-slide-toggle-appear.nav-slide-toggle-appear-active,
60-
.nav-slide-toggle-enter.nav-slide-toggle-enter-active {
61-
max-height: 1500px;
62-
transition: max-height 500ms ease-in;
63-
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, { Component } from 'react'
2+
import PropTypes from 'prop-types'
3+
import classNames from 'classnames'
4+
5+
import './NavigationMethod.scss'
6+
7+
export default class NavigationMethod extends Component {
8+
render () {
9+
const { method, isActive } = this.props
10+
11+
return (
12+
<a
13+
className={classNames('nav-method', {
14+
active: isActive
15+
})}
16+
key={method.link}
17+
href={`#${method.link}`}
18+
>
19+
<span className='method-type'>{method.type.toUpperCase()}</span>
20+
<span className='method-title'>{method.title}</span>
21+
</a>
22+
)
23+
}
24+
}
25+
26+
NavigationMethod.propTypes = {
27+
method: PropTypes.object,
28+
isActive: PropTypes.bool
29+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@import '../../base.scss';
2+
3+
.nav-method {
4+
display: block;
5+
margin: 5px 0;
6+
padding: 5px;
7+
font-size: smaller;
8+
color: black;
9+
10+
&.active {
11+
background-color: $grey-dark;
12+
}
13+
}
14+
15+
.method-title {
16+
padding-left: 5px;
17+
text-indent: 0;
18+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { Component } from 'react'
2+
import PropTypes from 'prop-types'
3+
4+
import Indicator from '../Indicator/Indicator'
5+
import NavigationMethod from '../NavigationMethod/NavigationMethod'
6+
7+
import './NavigationTag.scss'
8+
9+
export default class NavigationTag extends Component {
10+
constructor (props) {
11+
super(props)
12+
13+
this.handleClick = this.handleClick.bind(this)
14+
}
15+
16+
componentWillMount () {
17+
const { title, methods, location, onClick } = this.props
18+
19+
const method = methods.find(
20+
(method) => (`#${method.link}` === location.hash)
21+
)
22+
23+
if (method) {
24+
onClick(title)
25+
}
26+
}
27+
28+
handleClick (e) {
29+
this.props.onClick(this.props.title)
30+
}
31+
32+
render () {
33+
const { title, status, methods, location } = this.props
34+
35+
const isExpanded = (status === 'right')
36+
37+
return (
38+
<div key={title}>
39+
<a
40+
className='nav-tag'
41+
href={`#${title}`}
42+
onClick={this.handleClick}
43+
>
44+
{title}
45+
<Indicator status={status} />
46+
</a>
47+
<div className='nav-tag-methods'>
48+
{isExpanded && methods && methods.map((method) => {
49+
const isActive = (`#${method.link}` === location.hash)
50+
51+
return <NavigationMethod key={method.link} method={method} isActive={isActive} />
52+
})}
53+
</div>
54+
</div>
55+
)
56+
}
57+
}
58+
59+
NavigationTag.propTypes = {
60+
title: PropTypes.string.isRequired,
61+
methods: PropTypes.array,
62+
status: PropTypes.string,
63+
onClick: PropTypes.func.isRequired,
64+
location: PropTypes.object
65+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import '../../base.scss';
2+
3+
.nav-tag {
4+
display: block;
5+
text-transform: uppercase;
6+
font-weight: bold;
7+
color: $blue;
8+
9+
&.active {
10+
background-color: $grey-dark;
11+
}
12+
}

0 commit comments

Comments
 (0)