/
NavLink.js
90 lines (80 loc) · 2.25 KB
/
NavLink.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
import React from "react";
import { __RouterContext as RouterContext, matchPath } from "react-router";
import PropTypes from "prop-types";
import Link from "./Link";
import invariant from "tiny-invariant";
function joinClassnames(...classnames) {
return classnames.filter(i => i).join(" ");
}
/**
* A <Link> wrapper that knows if it's "active" or not.
*/
function NavLink({
"aria-current": ariaCurrent = "page",
activeClassName = "active",
activeStyle,
className: classNameProp,
exact,
isActive: isActiveProp,
location: locationProp,
strict,
style: styleProp,
to,
...rest
}) {
const path = typeof to === "object" ? to.pathname : to;
// Regex taken from: https://github.com/pillarjs/path-to-regexp/blob/master/index.js#L202
const escapedPath = path && path.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
return (
<RouterContext.Consumer>
{context => {
invariant(context, "You should not use <NavLink> outside a <Router>");
const pathToMatch = locationProp
? locationProp.pathname
: context.location.pathname;
const match = escapedPath
? matchPath(pathToMatch, { path: escapedPath, exact, strict })
: null;
const isActive = !!(isActiveProp
? isActiveProp(match, context.location)
: match);
const className = isActive
? joinClassnames(classNameProp, activeClassName)
: classNameProp;
const style = isActive ? { ...styleProp, ...activeStyle } : styleProp;
return (
<Link
aria-current={(isActive && ariaCurrent) || null}
className={className}
style={style}
to={to}
{...rest}
/>
);
}}
</RouterContext.Consumer>
);
}
if (__DEV__) {
const ariaCurrentType = PropTypes.oneOf([
"page",
"step",
"location",
"date",
"time",
"true"
]);
NavLink.propTypes = {
...Link.propTypes,
"aria-current": ariaCurrentType,
activeClassName: PropTypes.string,
activeStyle: PropTypes.object,
className: PropTypes.string,
exact: PropTypes.bool,
isActive: PropTypes.func,
location: PropTypes.object,
strict: PropTypes.bool,
style: PropTypes.object
};
}
export default NavLink;