-
Notifications
You must be signed in to change notification settings - Fork 23
/
index.js
104 lines (87 loc) · 2.66 KB
/
index.js
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
import React, {PropTypes as t} from 'react'
import Link from 'react-router/lib/Link'
import withRouter from 'react-router/lib/withRouter'
let {toString} = Object.prototype
let typeOf = o => toString.call(o).slice(8, -1).toLowerCase()
function createLocationDescriptor({to, query, hash, state}) {
if (typeOf(to) === 'string') {
return {pathname: to, query, hash, state}
}
return {query, hash, state, ...to}
}
function omitProps(props, omittedPropNames) {
const isOmittedProp = {}
omittedPropNames.forEach(propName => { isOmittedProp[propName] = true })
const elementProps = {}
Object.entries(props).forEach(([propName, propValue]) => {
if (!isOmittedProp[propName]) {
elementProps[propName] = propValue
}
})
return elementProps
}
module.exports = function activeComponent(Component, options) {
if (!Component) {
throw new Error('activeComponent() must be given a tag name or React component')
}
options = {
link: true,
linkClassName: undefined,
...options,
}
let ActiveComponent = React.createClass({
propTypes: {
activeClassName: t.string.isRequired,
router: t.object.isRequired,
to: t.oneOfType([t.string, t.object]).isRequired,
activeStyle: t.object,
className: t.string,
hash: t.string,
link: t.bool,
linkProps: t.object,
onlyActiveOnIndex: t.bool,
query: t.object,
},
getDefaultProps() {
return {
activeClassName: 'active',
link: options.link,
onlyActiveOnIndex: false,
}
},
render() {
let {
link, linkProps,
to, query, hash, state, onlyActiveOnIndex,
activeClassName, activeStyle,
router,
...props,
} = this.props
let location = createLocationDescriptor({to, query, hash, state})
if (router) {
let active = router.isActive(location, onlyActiveOnIndex)
if (typeOf(Component) !== 'string') {
props.active = active
}
if (active) {
if (activeClassName) {
props.className = `${props.className || ''}${props.className ? ' ' : ''}${activeClassName}`
}
if (activeStyle) {
props.style = {...props.style, activeStyle}
}
}
}
let componentProps = omitProps(props, ['params', 'location', 'routes'])
if (!link) {
return <Component {...componentProps}>{this.props.children}</Component>
}
return <Component {...componentProps}>
<Link className={options.linkClassName} {...linkProps} to={location}>
{this.props.children}
</Link>
</Component>
}
})
return withRouter(ActiveComponent)
}