1 |
3a515b92
|
cagy
|
import React from "react";
|
2 |
|
|
import { __RouterContext as RouterContext } from "react-router";
|
3 |
|
|
import PropTypes from "prop-types";
|
4 |
|
|
import invariant from "tiny-invariant";
|
5 |
|
|
import { resolveToLocation, normalizeToLocation } from "./utils/locationUtils";
|
6 |
|
|
|
7 |
|
|
// React 15 compat
|
8 |
|
|
const forwardRefShim = C => C;
|
9 |
|
|
let { forwardRef } = React;
|
10 |
|
|
if (typeof forwardRef === "undefined") {
|
11 |
|
|
forwardRef = forwardRefShim;
|
12 |
|
|
}
|
13 |
|
|
|
14 |
|
|
function isModifiedEvent(event) {
|
15 |
|
|
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
16 |
|
|
}
|
17 |
|
|
|
18 |
|
|
const LinkAnchor = forwardRef(
|
19 |
|
|
(
|
20 |
|
|
{
|
21 |
|
|
innerRef, // TODO: deprecate
|
22 |
|
|
navigate,
|
23 |
|
|
onClick,
|
24 |
|
|
...rest
|
25 |
|
|
},
|
26 |
|
|
forwardedRef
|
27 |
|
|
) => {
|
28 |
|
|
const { target } = rest;
|
29 |
|
|
|
30 |
|
|
let props = {
|
31 |
|
|
...rest,
|
32 |
|
|
onClick: event => {
|
33 |
|
|
try {
|
34 |
|
|
if (onClick) onClick(event);
|
35 |
|
|
} catch (ex) {
|
36 |
|
|
event.preventDefault();
|
37 |
|
|
throw ex;
|
38 |
|
|
}
|
39 |
|
|
|
40 |
|
|
if (
|
41 |
|
|
!event.defaultPrevented && // onClick prevented default
|
42 |
|
|
event.button === 0 && // ignore everything but left clicks
|
43 |
|
|
(!target || target === "_self") && // let browser handle "target=_blank" etc.
|
44 |
|
|
!isModifiedEvent(event) // ignore clicks with modifier keys
|
45 |
|
|
) {
|
46 |
|
|
event.preventDefault();
|
47 |
|
|
navigate();
|
48 |
|
|
}
|
49 |
|
|
}
|
50 |
|
|
};
|
51 |
|
|
|
52 |
|
|
// React 15 compat
|
53 |
|
|
if (forwardRefShim !== forwardRef) {
|
54 |
|
|
props.ref = forwardedRef || innerRef;
|
55 |
|
|
} else {
|
56 |
|
|
props.ref = innerRef;
|
57 |
|
|
}
|
58 |
|
|
|
59 |
|
|
return <a {...props} />;
|
60 |
|
|
}
|
61 |
|
|
);
|
62 |
|
|
|
63 |
|
|
if (__DEV__) {
|
64 |
|
|
LinkAnchor.displayName = "LinkAnchor";
|
65 |
|
|
}
|
66 |
|
|
|
67 |
|
|
/**
|
68 |
|
|
* The public API for rendering a history-aware <a>.
|
69 |
|
|
*/
|
70 |
|
|
const Link = forwardRef(
|
71 |
|
|
(
|
72 |
|
|
{
|
73 |
|
|
component = LinkAnchor,
|
74 |
|
|
replace,
|
75 |
|
|
to,
|
76 |
|
|
innerRef, // TODO: deprecate
|
77 |
|
|
...rest
|
78 |
|
|
},
|
79 |
|
|
forwardedRef
|
80 |
|
|
) => {
|
81 |
|
|
return (
|
82 |
|
|
<RouterContext.Consumer>
|
83 |
|
|
{context => {
|
84 |
|
|
invariant(context, "You should not use <Link> outside a <Router>");
|
85 |
|
|
|
86 |
|
|
const { history } = context;
|
87 |
|
|
|
88 |
|
|
const location = normalizeToLocation(
|
89 |
|
|
resolveToLocation(to, context.location),
|
90 |
|
|
context.location
|
91 |
|
|
);
|
92 |
|
|
|
93 |
|
|
const href = location ? history.createHref(location) : "";
|
94 |
|
|
const props = {
|
95 |
|
|
...rest,
|
96 |
|
|
href,
|
97 |
|
|
navigate() {
|
98 |
|
|
const location = resolveToLocation(to, context.location);
|
99 |
|
|
const method = replace ? history.replace : history.push;
|
100 |
|
|
|
101 |
|
|
method(location);
|
102 |
|
|
}
|
103 |
|
|
};
|
104 |
|
|
|
105 |
|
|
// React 15 compat
|
106 |
|
|
if (forwardRefShim !== forwardRef) {
|
107 |
|
|
props.ref = forwardedRef || innerRef;
|
108 |
|
|
} else {
|
109 |
|
|
props.innerRef = innerRef;
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
return React.createElement(component, props);
|
113 |
|
|
}}
|
114 |
|
|
</RouterContext.Consumer>
|
115 |
|
|
);
|
116 |
|
|
}
|
117 |
|
|
);
|
118 |
|
|
|
119 |
|
|
if (__DEV__) {
|
120 |
|
|
const toType = PropTypes.oneOfType([
|
121 |
|
|
PropTypes.string,
|
122 |
|
|
PropTypes.object,
|
123 |
|
|
PropTypes.func
|
124 |
|
|
]);
|
125 |
|
|
const refType = PropTypes.oneOfType([
|
126 |
|
|
PropTypes.string,
|
127 |
|
|
PropTypes.func,
|
128 |
|
|
PropTypes.shape({ current: PropTypes.any })
|
129 |
|
|
]);
|
130 |
|
|
|
131 |
|
|
Link.displayName = "Link";
|
132 |
|
|
|
133 |
|
|
Link.propTypes = {
|
134 |
|
|
innerRef: refType,
|
135 |
|
|
onClick: PropTypes.func,
|
136 |
|
|
replace: PropTypes.bool,
|
137 |
|
|
target: PropTypes.string,
|
138 |
|
|
to: toType.isRequired
|
139 |
|
|
};
|
140 |
|
|
}
|
141 |
|
|
|
142 |
|
|
export default Link;
|