@tdb/web
Version:
Common condiguration for serving a web-site and testing web-based UI components.
241 lines (180 loc) • 8.4 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime-corejs2/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/typeof"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/assertThisInitialized"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
var _url = require("url");
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _router = _interopRequireWildcard(require("./router"));
var _utils = require("./utils");
/* global __NEXT_DATA__ */
function isLocal(href) {
var url = (0, _url.parse)(href, false, true);
var origin = (0, _url.parse)((0, _utils.getLocationOrigin)(), false, true);
return !url.host || url.protocol === origin.protocol && url.host === origin.host;
}
function memoizedFormatUrl(formatUrl) {
var lastHref = null;
var lastAs = null;
var lastResult = null;
return function (href, as) {
if (href === lastHref && as === lastAs) {
return lastResult;
}
var result = formatUrl(href, as);
lastHref = href;
lastAs = as;
lastResult = result;
return result;
};
}
var Link =
/*#__PURE__*/
function (_Component) {
(0, _inherits2.default)(Link, _Component);
function Link() {
var _getPrototypeOf2;
var _this;
(0, _classCallCheck2.default)(this, Link);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(Link)).call.apply(_getPrototypeOf2, [this].concat(args)));
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "formatUrls", memoizedFormatUrl(function (href, asHref) {
return {
href: href && (0, _typeof2.default)(href) === 'object' ? (0, _url.format)(href) : href,
as: asHref && (0, _typeof2.default)(asHref) === 'object' ? (0, _url.format)(asHref) : asHref
};
}));
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "linkClicked", function (e) {
var _e$currentTarget = e.currentTarget,
nodeName = _e$currentTarget.nodeName,
target = _e$currentTarget.target;
if (nodeName === 'A' && (target && target !== '_self' || e.metaKey || e.ctrlKey || e.shiftKey || e.nativeEvent && e.nativeEvent.which === 2)) {
// ignore click for new tab / new window behavior
return;
}
var _this$formatUrls = _this.formatUrls(_this.props.href, _this.props.as),
href = _this$formatUrls.href,
as = _this$formatUrls.as;
if (!isLocal(href)) {
// ignore click if it's outside our scope
return;
}
var pathname = window.location.pathname;
href = (0, _url.resolve)(pathname, href);
as = as ? (0, _url.resolve)(pathname, as) : href;
e.preventDefault(); // avoid scroll for urls with anchor refs
var scroll = _this.props.scroll;
if (scroll == null) {
scroll = as.indexOf('#') < 0;
} // replace state instead of push if prop is present
var replace = _this.props.replace;
var changeMethod = replace ? 'replace' : 'push'; // straight up redirect
_router.default[changeMethod](href, as, {
shallow: _this.props.shallow
}).then(function (success) {
if (!success) return;
if (scroll) {
window.scrollTo(0, 0);
document.body.focus();
}
}).catch(function (err) {
if (_this.props.onError) _this.props.onError(err);
});
});
return _this;
}
(0, _createClass2.default)(Link, [{
key: "componentDidMount",
value: function componentDidMount() {
this.prefetch();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
if ((0, _stringify.default)(this.props.href) !== (0, _stringify.default)(prevProps.href)) {
this.prefetch();
}
} // The function is memoized so that no extra lifecycles are needed
// as per https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
}, {
key: "prefetch",
value: function prefetch() {
if (!this.props.prefetch) return;
if (typeof window === 'undefined') return; // Prefetch the JSON page if asked (only in the client)
var pathname = window.location.pathname;
var _this$formatUrls2 = this.formatUrls(this.props.href, this.props.as),
parsedHref = _this$formatUrls2.href;
var href = (0, _url.resolve)(pathname, parsedHref);
_router.default.prefetch(href);
}
}, {
key: "render",
value: function render() {
var _this2 = this;
var children = this.props.children;
var _this$formatUrls3 = this.formatUrls(this.props.href, this.props.as),
href = _this$formatUrls3.href,
as = _this$formatUrls3.as; // Deprecated. Warning shown by propType check. If the childen provided is a string (<Link>example</Link>) we wrap it in an <a> tag
if (typeof children === 'string') {
children = _react.default.createElement("a", null, children);
} // This will return the first child, if multiple are provided it will throw an error
var child = _react.Children.only(children);
var props = {
onClick: function onClick(e) {
if (child.props && typeof child.props.onClick === 'function') {
child.props.onClick(e);
}
if (!e.defaultPrevented) {
_this2.linkClicked(e);
}
} // If child is an <a> tag and doesn't have a href attribute, or if the 'passHref' property is
// defined, we specify the current 'href', so that repetition is not needed by the user
};
if (this.props.passHref || child.type === 'a' && !('href' in child.props)) {
props.href = as || href;
} // Add the ending slash to the paths. So, we can serve the
// "<page>/index.html" directly.
if (props.href && typeof __NEXT_DATA__ !== 'undefined' && __NEXT_DATA__.nextExport) {
props.href = (0, _router._rewriteUrlForNextExport)(props.href);
}
return _react.default.cloneElement(child, props);
}
}]);
return Link;
}(_react.Component);
if (process.env.NODE_ENV === 'development') {
var warn = (0, _utils.execOnce)(console.error); // This module gets removed by webpack.IgnorePlugin
var exact = require('prop-types-exact');
Link.propTypes = exact({
href: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]).isRequired,
as: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]),
prefetch: _propTypes.default.bool,
replace: _propTypes.default.bool,
shallow: _propTypes.default.bool,
passHref: _propTypes.default.bool,
scroll: _propTypes.default.bool,
children: _propTypes.default.oneOfType([_propTypes.default.element, function (props, propName) {
var value = props[propName];
if (typeof value === 'string') {
warn("Warning: You're using a string directly inside <Link>. This usage has been deprecated. Please add an <a> tag as child of <Link>");
}
return null;
}]).isRequired
});
}
var _default = Link;
exports.default = _default;