123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import React from "react";
- import { __RouterContext as RouterContext } from "react-router";
- import PropTypes from "prop-types";
- import invariant from "tiny-invariant";
- import {
- resolveToLocation,
- normalizeToLocation
- } from "./utils/locationUtils.js";
- // React 15 compat
- const forwardRefShim = C => C;
- let { forwardRef } = React;
- if (typeof forwardRef === "undefined") {
- forwardRef = forwardRefShim;
- }
- function isModifiedEvent(event) {
- return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
- }
- const LinkAnchor = forwardRef(
- (
- {
- innerRef, // TODO: deprecate
- navigate,
- onClick,
- ...rest
- },
- forwardedRef
- ) => {
- const { target } = rest;
- let props = {
- ...rest,
- onClick: event => {
- try {
- if (onClick) onClick(event);
- } catch (ex) {
- event.preventDefault();
- throw ex;
- }
- if (
- !event.defaultPrevented && // onClick prevented default
- event.button === 0 && // ignore everything but left clicks
- (!target || target === "_self") && // let browser handle "target=_blank" etc.
- !isModifiedEvent(event) // ignore clicks with modifier keys
- ) {
- event.preventDefault();
- navigate();
- }
- }
- };
- // React 15 compat
- if (forwardRefShim !== forwardRef) {
- props.ref = forwardedRef || innerRef;
- } else {
- props.ref = innerRef;
- }
- /* eslint-disable-next-line jsx-a11y/anchor-has-content */
- return <a {...props} />;
- }
- );
- if (__DEV__) {
- LinkAnchor.displayName = "LinkAnchor";
- }
- /**
- * The public API for rendering a history-aware <a>.
- */
- const Link = forwardRef(
- (
- {
- component = LinkAnchor,
- replace,
- to,
- innerRef, // TODO: deprecate
- ...rest
- },
- forwardedRef
- ) => {
- return (
- <RouterContext.Consumer>
- {context => {
- invariant(context, "You should not use <Link> outside a <Router>");
- const { history } = context;
- const location = normalizeToLocation(
- resolveToLocation(to, context.location),
- context.location
- );
- const href = location ? history.createHref(location) : "";
- const props = {
- ...rest,
- href,
- navigate() {
- const location = resolveToLocation(to, context.location);
- const method = replace ? history.replace : history.push;
- method(location);
- }
- };
- // React 15 compat
- if (forwardRefShim !== forwardRef) {
- props.ref = forwardedRef || innerRef;
- } else {
- props.innerRef = innerRef;
- }
- return React.createElement(component, props);
- }}
- </RouterContext.Consumer>
- );
- }
- );
- if (__DEV__) {
- const toType = PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.object,
- PropTypes.func
- ]);
- const refType = PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.func,
- PropTypes.shape({ current: PropTypes.any })
- ]);
- Link.displayName = "Link";
- Link.propTypes = {
- innerRef: refType,
- onClick: PropTypes.func,
- replace: PropTypes.bool,
- target: PropTypes.string,
- to: toType.isRequired
- };
- }
- export default Link;
|