Files
30-seconds-of-code/node_modules/@reach/router/index.js
2019-08-20 15:52:05 +02:00

655 lines
22 KiB
JavaScript

"use strict";
exports.__esModule = true;
exports.globalHistory = exports.redirectTo = exports.navigate = exports.isRedirect = exports.createMemorySource = exports.createHistory = exports.ServerLocation = exports.Router = exports.Redirect = exports.Match = exports.LocationProvider = exports.Location = exports.Link = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _warning = require("warning");
var _warning2 = _interopRequireDefault(_warning);
var _propTypes = require("prop-types");
var _propTypes2 = _interopRequireDefault(_propTypes);
var _invariant = require("invariant");
var _invariant2 = _interopRequireDefault(_invariant);
var _createReactContext = require("create-react-context");
var _createReactContext2 = _interopRequireDefault(_createReactContext);
var _reactLifecyclesCompat = require("react-lifecycles-compat");
var _utils = require("./lib/utils");
var _history = require("./lib/history");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /* eslint-disable jsx-a11y/anchor-has-content */
////////////////////////////////////////////////////////////////////////////////
var createNamedContext = function createNamedContext(name, defaultValue) {
var Ctx = (0, _createReactContext2.default)(defaultValue);
Ctx.Consumer.displayName = name + ".Consumer";
Ctx.Provider.displayName = name + ".Provider";
return Ctx;
};
////////////////////////////////////////////////////////////////////////////////
// Location Context/Provider
var LocationContext = createNamedContext("Location");
// sets up a listener if there isn't one already so apps don't need to be
// wrapped in some top level provider
var Location = function Location(_ref) {
var children = _ref.children;
return _react2.default.createElement(
LocationContext.Consumer,
null,
function (context) {
return context ? children(context) : _react2.default.createElement(
LocationProvider,
null,
children
);
}
);
};
var LocationProvider = function (_React$Component) {
_inherits(LocationProvider, _React$Component);
function LocationProvider() {
var _temp, _this, _ret;
_classCallCheck(this, LocationProvider);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {
context: _this.getContext(),
refs: { unlisten: null }
}, _temp), _possibleConstructorReturn(_this, _ret);
}
LocationProvider.prototype.getContext = function getContext() {
var _props$history = this.props.history,
navigate = _props$history.navigate,
location = _props$history.location;
return { navigate: navigate, location: location };
};
LocationProvider.prototype.componentDidCatch = function componentDidCatch(error, info) {
if (isRedirect(error)) {
var _navigate = this.props.history.navigate;
_navigate(error.uri, { replace: true });
} else {
throw error;
}
};
LocationProvider.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
if (prevState.context.location !== this.state.context.location) {
this.props.history._onTransitionComplete();
}
};
LocationProvider.prototype.componentDidMount = function componentDidMount() {
var _this2 = this;
var refs = this.state.refs,
history = this.props.history;
refs.unlisten = history.listen(function () {
Promise.resolve().then(function () {
// TODO: replace rAF with react deferred update API when it's ready https://github.com/facebook/react/issues/13306
requestAnimationFrame(function () {
if (!_this2.unmounted) {
_this2.setState(function () {
return { context: _this2.getContext() };
});
}
});
});
});
};
LocationProvider.prototype.componentWillUnmount = function componentWillUnmount() {
var refs = this.state.refs;
this.unmounted = true;
refs.unlisten();
};
LocationProvider.prototype.render = function render() {
var context = this.state.context,
children = this.props.children;
return _react2.default.createElement(
LocationContext.Provider,
{ value: context },
typeof children === "function" ? children(context) : children || null
);
};
return LocationProvider;
}(_react2.default.Component);
////////////////////////////////////////////////////////////////////////////////
LocationProvider.defaultProps = {
history: _history.globalHistory
};
process.env.NODE_ENV !== "production" ? LocationProvider.propTypes = {
history: _propTypes2.default.object.isRequired
} : void 0;
var ServerLocation = function ServerLocation(_ref2) {
var url = _ref2.url,
children = _ref2.children;
return _react2.default.createElement(
LocationContext.Provider,
{
value: {
location: {
pathname: url,
search: "",
hash: ""
},
navigate: function navigate() {
throw new Error("You can't call navigate on the server.");
}
}
},
children
);
};
////////////////////////////////////////////////////////////////////////////////
// Sets baseuri and basepath for nested routers and links
var BaseContext = createNamedContext("Base", { baseuri: "/", basepath: "/" });
////////////////////////////////////////////////////////////////////////////////
// The main event, welcome to the show everybody.
var Router = function Router(props) {
return _react2.default.createElement(
BaseContext.Consumer,
null,
function (baseContext) {
return _react2.default.createElement(
Location,
null,
function (locationContext) {
return _react2.default.createElement(RouterImpl, _extends({}, baseContext, locationContext, props));
}
);
}
);
};
var RouterImpl = function (_React$PureComponent) {
_inherits(RouterImpl, _React$PureComponent);
function RouterImpl() {
_classCallCheck(this, RouterImpl);
return _possibleConstructorReturn(this, _React$PureComponent.apply(this, arguments));
}
RouterImpl.prototype.render = function render() {
var _props = this.props,
location = _props.location,
_navigate2 = _props.navigate,
basepath = _props.basepath,
primary = _props.primary,
children = _props.children,
baseuri = _props.baseuri,
_props$component = _props.component,
component = _props$component === undefined ? "div" : _props$component,
domProps = _objectWithoutProperties(_props, ["location", "navigate", "basepath", "primary", "children", "baseuri", "component"]);
var routes = _react2.default.Children.map(children, createRoute(basepath));
var pathname = location.pathname;
var match = (0, _utils.pick)(routes, pathname);
if (match) {
var params = match.params,
uri = match.uri,
route = match.route,
element = match.route.value;
// remove the /* from the end for child routes relative paths
basepath = route.default ? basepath : route.path.replace(/\*$/, "");
var props = _extends({}, params, {
uri: uri,
location: location,
navigate: function navigate(to, options) {
return _navigate2((0, _utils.resolve)(to, uri), options);
}
});
var clone = _react2.default.cloneElement(element, props, element.props.children ? _react2.default.createElement(
Router,
{ primary: primary },
element.props.children
) : undefined);
// using 'div' for < 16.3 support
var FocusWrapper = primary ? FocusHandler : component;
// don't pass any props to 'div'
var wrapperProps = primary ? _extends({ uri: uri, location: location, component: component }, domProps) : domProps;
return _react2.default.createElement(
BaseContext.Provider,
{ value: { baseuri: uri, basepath: basepath } },
_react2.default.createElement(
FocusWrapper,
wrapperProps,
clone
)
);
} else {
// Not sure if we want this, would require index routes at every level
// warning(
// false,
// `<Router basepath="${basepath}">\n\nNothing matched:\n\t${
// location.pathname
// }\n\nPaths checked: \n\t${routes
// .map(route => route.path)
// .join(
// "\n\t"
// )}\n\nTo get rid of this warning, add a default NotFound component as child of Router:
// \n\tlet NotFound = () => <div>Not Found!</div>
// \n\t<Router>\n\t <NotFound default/>\n\t {/* ... */}\n\t</Router>`
// );
return null;
}
};
return RouterImpl;
}(_react2.default.PureComponent);
RouterImpl.defaultProps = {
primary: true
};
var FocusContext = createNamedContext("Focus");
var FocusHandler = function FocusHandler(_ref3) {
var uri = _ref3.uri,
location = _ref3.location,
component = _ref3.component,
domProps = _objectWithoutProperties(_ref3, ["uri", "location", "component"]);
return _react2.default.createElement(
FocusContext.Consumer,
null,
function (requestFocus) {
return _react2.default.createElement(FocusHandlerImpl, _extends({}, domProps, {
component: component,
requestFocus: requestFocus,
uri: uri,
location: location
}));
}
);
};
// don't focus on initial render
var initialRender = true;
var focusHandlerCount = 0;
var FocusHandlerImpl = function (_React$Component2) {
_inherits(FocusHandlerImpl, _React$Component2);
function FocusHandlerImpl() {
var _temp2, _this4, _ret2;
_classCallCheck(this, FocusHandlerImpl);
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return _ret2 = (_temp2 = (_this4 = _possibleConstructorReturn(this, _React$Component2.call.apply(_React$Component2, [this].concat(args))), _this4), _this4.state = {}, _this4.requestFocus = function (node) {
if (!_this4.state.shouldFocus) {
node.focus();
}
}, _temp2), _possibleConstructorReturn(_this4, _ret2);
}
FocusHandlerImpl.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
var initial = prevState.uri == null;
if (initial) {
return _extends({
shouldFocus: true
}, nextProps);
} else {
var myURIChanged = nextProps.uri !== prevState.uri;
var navigatedUpToMe = prevState.location.pathname !== nextProps.location.pathname && nextProps.location.pathname === nextProps.uri;
return _extends({
shouldFocus: myURIChanged || navigatedUpToMe
}, nextProps);
}
};
FocusHandlerImpl.prototype.componentDidMount = function componentDidMount() {
focusHandlerCount++;
this.focus();
};
FocusHandlerImpl.prototype.componentWillUnmount = function componentWillUnmount() {
focusHandlerCount--;
if (focusHandlerCount === 0) {
initialRender = true;
}
};
FocusHandlerImpl.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
if (prevProps.location !== this.props.location && this.state.shouldFocus) {
this.focus();
}
};
FocusHandlerImpl.prototype.focus = function focus() {
if (process.env.NODE_ENV === "test") {
// getting cannot read property focus of null in the tests
// and that bit of global `initialRender` state causes problems
// should probably figure it out!
return;
}
var requestFocus = this.props.requestFocus;
if (requestFocus) {
requestFocus(this.node);
} else {
if (initialRender) {
initialRender = false;
} else {
// React polyfills [autofocus] and it fires earlier than cDM,
// so we were stealing focus away, this line prevents that.
if (!this.node.contains(document.activeElement)) {
this.node.focus();
}
}
}
};
FocusHandlerImpl.prototype.render = function render() {
var _this5 = this;
var _props2 = this.props,
children = _props2.children,
style = _props2.style,
requestFocus = _props2.requestFocus,
_props2$role = _props2.role,
role = _props2$role === undefined ? "group" : _props2$role,
_props2$component = _props2.component,
Comp = _props2$component === undefined ? "div" : _props2$component,
uri = _props2.uri,
location = _props2.location,
domProps = _objectWithoutProperties(_props2, ["children", "style", "requestFocus", "role", "component", "uri", "location"]);
return _react2.default.createElement(
Comp,
_extends({
style: _extends({ outline: "none" }, style),
tabIndex: "-1",
role: role,
ref: function ref(n) {
return _this5.node = n;
}
}, domProps),
_react2.default.createElement(
FocusContext.Provider,
{ value: this.requestFocus },
this.props.children
)
);
};
return FocusHandlerImpl;
}(_react2.default.Component);
(0, _reactLifecyclesCompat.polyfill)(FocusHandlerImpl);
var k = function k() {};
////////////////////////////////////////////////////////////////////////////////
var forwardRef = _react2.default.forwardRef;
if (typeof forwardRef === "undefined") {
forwardRef = function forwardRef(C) {
return C;
};
}
var Link = forwardRef(function (_ref4, ref) {
var innerRef = _ref4.innerRef,
props = _objectWithoutProperties(_ref4, ["innerRef"]);
return _react2.default.createElement(
BaseContext.Consumer,
null,
function (_ref5) {
var basepath = _ref5.basepath,
baseuri = _ref5.baseuri;
return _react2.default.createElement(
Location,
null,
function (_ref6) {
var location = _ref6.location,
navigate = _ref6.navigate;
var to = props.to,
state = props.state,
replace = props.replace,
_props$getProps = props.getProps,
getProps = _props$getProps === undefined ? k : _props$getProps,
anchorProps = _objectWithoutProperties(props, ["to", "state", "replace", "getProps"]);
var href = (0, _utils.resolve)(to, baseuri);
var isCurrent = location.pathname === href;
var isPartiallyCurrent = (0, _utils.startsWith)(location.pathname, href);
return _react2.default.createElement("a", _extends({
ref: ref || innerRef,
"aria-current": isCurrent ? "page" : undefined
}, anchorProps, getProps({ isCurrent: isCurrent, isPartiallyCurrent: isPartiallyCurrent, href: href, location: location }), {
href: href,
onClick: function onClick(event) {
if (anchorProps.onClick) anchorProps.onClick(event);
if (shouldNavigate(event)) {
event.preventDefault();
navigate(href, { state: state, replace: replace });
}
}
}));
}
);
}
);
});
////////////////////////////////////////////////////////////////////////////////
function RedirectRequest(uri) {
this.uri = uri;
}
var isRedirect = function isRedirect(o) {
return o instanceof RedirectRequest;
};
var redirectTo = function redirectTo(to) {
throw new RedirectRequest(to);
};
var RedirectImpl = function (_React$Component3) {
_inherits(RedirectImpl, _React$Component3);
function RedirectImpl() {
_classCallCheck(this, RedirectImpl);
return _possibleConstructorReturn(this, _React$Component3.apply(this, arguments));
}
// Support React < 16 with this hook
RedirectImpl.prototype.componentDidMount = function componentDidMount() {
var _props3 = this.props,
navigate = _props3.navigate,
to = _props3.to,
from = _props3.from,
_props3$replace = _props3.replace,
replace = _props3$replace === undefined ? true : _props3$replace,
state = _props3.state,
noThrow = _props3.noThrow,
props = _objectWithoutProperties(_props3, ["navigate", "to", "from", "replace", "state", "noThrow"]);
Promise.resolve().then(function () {
navigate((0, _utils.insertParams)(to, props), { replace: replace, state: state });
});
};
RedirectImpl.prototype.render = function render() {
var _props4 = this.props,
navigate = _props4.navigate,
to = _props4.to,
from = _props4.from,
replace = _props4.replace,
state = _props4.state,
noThrow = _props4.noThrow,
props = _objectWithoutProperties(_props4, ["navigate", "to", "from", "replace", "state", "noThrow"]);
if (!noThrow) redirectTo((0, _utils.insertParams)(to, props));
return null;
};
return RedirectImpl;
}(_react2.default.Component);
var Redirect = function Redirect(props) {
return _react2.default.createElement(
Location,
null,
function (locationContext) {
return _react2.default.createElement(RedirectImpl, _extends({}, locationContext, props));
}
);
};
process.env.NODE_ENV !== "production" ? Redirect.propTypes = {
from: _propTypes2.default.string,
to: _propTypes2.default.string.isRequired
} : void 0;
////////////////////////////////////////////////////////////////////////////////
var Match = function Match(_ref7) {
var path = _ref7.path,
children = _ref7.children;
return _react2.default.createElement(
BaseContext.Consumer,
null,
function (_ref8) {
var baseuri = _ref8.baseuri;
return _react2.default.createElement(
Location,
null,
function (_ref9) {
var navigate = _ref9.navigate,
location = _ref9.location;
var resolvedPath = (0, _utils.resolve)(path, baseuri);
var result = (0, _utils.match)(resolvedPath, location.pathname);
return children({
navigate: navigate,
location: location,
match: result ? _extends({}, result.params, {
uri: result.uri,
path: path
}) : null
});
}
);
}
);
};
////////////////////////////////////////////////////////////////////////////////
// Junk
var stripSlashes = function stripSlashes(str) {
return str.replace(/(^\/+|\/+$)/g, "");
};
var createRoute = function createRoute(basepath) {
return function (element) {
if (!element) {
return null;
}
!(element.props.path || element.props.default || element.type === Redirect) ? process.env.NODE_ENV !== "production" ? (0, _invariant2.default)(false, "<Router>: Children of <Router> must have a `path` or `default` prop, or be a `<Redirect>`. None found on element type `" + element.type + "`") : (0, _invariant2.default)(false) : void 0;
!!(element.type === Redirect && (!element.props.from || !element.props.to)) ? process.env.NODE_ENV !== "production" ? (0, _invariant2.default)(false, "<Redirect from=\"" + element.props.from + " to=\"" + element.props.to + "\"/> requires both \"from\" and \"to\" props when inside a <Router>.") : (0, _invariant2.default)(false) : void 0;
!!(element.type === Redirect && !(0, _utils.validateRedirect)(element.props.from, element.props.to)) ? process.env.NODE_ENV !== "production" ? (0, _invariant2.default)(false, "<Redirect from=\"" + element.props.from + " to=\"" + element.props.to + "\"/> has mismatched dynamic segments, ensure both paths have the exact same dynamic segments.") : (0, _invariant2.default)(false) : void 0;
if (element.props.default) {
return { value: element, default: true };
}
var elementPath = element.type === Redirect ? element.props.from : element.props.path;
var path = elementPath === "/" ? basepath : stripSlashes(basepath) + "/" + stripSlashes(elementPath);
return {
value: element,
default: element.props.default,
path: element.props.children ? stripSlashes(path) + "/*" : path
};
};
};
var shouldNavigate = function shouldNavigate(event) {
return !event.defaultPrevented && event.button === 0 && !(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
};
////////////////////////////////////////////////////////////////////////
exports.Link = Link;
exports.Location = Location;
exports.LocationProvider = LocationProvider;
exports.Match = Match;
exports.Redirect = Redirect;
exports.Router = Router;
exports.ServerLocation = ServerLocation;
exports.createHistory = _history.createHistory;
exports.createMemorySource = _history.createMemorySource;
exports.isRedirect = isRedirect;
exports.navigate = _history.navigate;
exports.redirectTo = redirectTo;
exports.globalHistory = _history.globalHistory;