Projekt

Obecné

Profil

Stáhnout (3.06 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
import React from "react";
2
import { __RouterContext as RouterContext, matchPath } from "react-router";
3
import PropTypes from "prop-types";
4
import invariant from "tiny-invariant";
5
import Link from "./Link";
6
import { resolveToLocation, normalizeToLocation } from "./utils/locationUtils";
7
8
// React 15 compat
9
const forwardRefShim = C => C;
10
let { forwardRef } = React;
11
if (typeof forwardRef === "undefined") {
12
  forwardRef = forwardRefShim;
13
}
14
15
function joinClassnames(...classnames) {
16
  return classnames.filter(i => i).join(" ");
17
}
18
19
/**
20
 * A <Link> wrapper that knows if it's "active" or not.
21
 */
22
const NavLink = forwardRef(
23
  (
24
    {
25
      "aria-current": ariaCurrent = "page",
26
      activeClassName = "active",
27
      activeStyle,
28
      className: classNameProp,
29
      exact,
30
      isActive: isActiveProp,
31
      location: locationProp,
32
      strict,
33
      style: styleProp,
34
      to,
35
      innerRef, // TODO: deprecate
36
      ...rest
37
    },
38
    forwardedRef
39
  ) => {
40
    return (
41
      <RouterContext.Consumer>
42
        {context => {
43
          invariant(context, "You should not use <NavLink> outside a <Router>");
44
45
          const currentLocation = locationProp || context.location;
46
          const toLocation = normalizeToLocation(
47
            resolveToLocation(to, currentLocation),
48
            currentLocation
49
          );
50
          const { pathname: path } = toLocation;
51
          // Regex taken from: https://github.com/pillarjs/path-to-regexp/blob/master/index.js#L202
52
          const escapedPath =
53
            path && path.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
54
55
          const match = escapedPath
56
            ? matchPath(currentLocation.pathname, {
57
                path: escapedPath,
58
                exact,
59
                strict
60
              })
61
            : null;
62
          const isActive = !!(isActiveProp
63
            ? isActiveProp(match, currentLocation)
64
            : match);
65
66
          const className = isActive
67
            ? joinClassnames(classNameProp, activeClassName)
68
            : classNameProp;
69
          const style = isActive ? { ...styleProp, ...activeStyle } : styleProp;
70
71
          const props = {
72
            "aria-current": (isActive && ariaCurrent) || null,
73
            className,
74
            style,
75
            to: toLocation,
76
            ...rest
77
          };
78
79
          // React 15 compat
80
          if (forwardRefShim !== forwardRef) {
81
            props.ref = forwardedRef || innerRef;
82
          } else {
83
            props.innerRef = innerRef;
84
          }
85
86
          return <Link {...props} />;
87
        }}
88
      </RouterContext.Consumer>
89
    );
90
  }
91
);
92
93
if (__DEV__) {
94
  NavLink.displayName = "NavLink";
95
96
  const ariaCurrentType = PropTypes.oneOf([
97
    "page",
98
    "step",
99
    "location",
100
    "date",
101
    "time",
102
    "true"
103
  ]);
104
105
  NavLink.propTypes = {
106
    ...Link.propTypes,
107
    "aria-current": ariaCurrentType,
108
    activeClassName: PropTypes.string,
109
    activeStyle: PropTypes.object,
110
    className: PropTypes.string,
111
    exact: PropTypes.bool,
112
    isActive: PropTypes.func,
113
    location: PropTypes.object,
114
    strict: PropTypes.bool,
115
    style: PropTypes.object
116
  };
117
}
118
119
export default NavLink;