@shopify/react-async
Version:
Tools for creating powerful, asynchronously-loaded React components.
144 lines (143 loc) • 6.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var prefetch_1 = require("./context/prefetch");
var EventListener_1 = require("./EventListener");
exports.INTENTION_DELAY_MS = 150;
var ConnectedPrefetcher = /** @class */ (function (_super) {
tslib_1.__extends(ConnectedPrefetcher, _super);
function ConnectedPrefetcher() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.state = {};
_this.prefetchAgressively = shouldPrefetchAggressively();
_this.handlePressStart = function (_a) {
var target = _a.target;
_this.clearTimeout();
if (target == null) {
return;
}
var url = closestUrlFromNode(target);
if (url != null) {
_this.setState({ url: url });
}
};
_this.handlePointerLeave = function (_a) {
var target = _a.target, relatedTarget = _a.relatedTarget;
var url = _this.state.url;
var _b = _this, timeout = _b.timeout, timeoutUrl = _b.timeoutUrl;
if (target == null) {
if (timeout) {
_this.clearTimeout();
}
return;
}
if (url == null && timeout == null) {
return;
}
var closestUrl = closestUrlFromNode(target);
var relatedUrl = relatedTarget && closestUrlFromNode(relatedTarget);
if (timeout != null &&
urlsEqual(closestUrl, timeoutUrl) &&
!urlsEqual(relatedUrl, timeoutUrl)) {
_this.clearTimeout();
}
if (urlsEqual(closestUrl, url) && !urlsEqual(relatedUrl, url)) {
_this.setState({ url: undefined });
}
};
_this.handlePointerEnter = function (_a) {
var target = _a.target;
if (target == null) {
return;
}
var _b = _this, timeoutUrl = _b.timeoutUrl, timeout = _b.timeout;
var url = closestUrlFromNode(target);
if (url == null) {
return;
}
if (timeout) {
if (urlsEqual(url, timeoutUrl)) {
return;
}
else {
_this.clearTimeout();
}
}
_this.timeoutUrl = url;
_this.timeout = setTimeout(function () {
_this.clearTimeout();
_this.setState({ url: url });
}, exports.INTENTION_DELAY_MS);
};
return _this;
}
ConnectedPrefetcher.prototype.render = function () {
var url = this.state.url;
var manager = this.props.manager;
var preloadMarkup = url ? (React.createElement("div", { style: { visibility: 'hidden' } }, findMatches(manager.registered, url).map(function (_a, index) {
var render = _a.render, path = _a.path;
// eslint-disable-next-line react/no-array-index-key
return React.createElement("div", { key: "" + path + index }, render(url));
}))) : null;
var expensiveListeners = this.prefetchAgressively ? (React.createElement(React.Fragment, null,
React.createElement(EventListener_1.EventListener, { passive: true, event: "mouseover", handler: this.handlePointerEnter }),
React.createElement(EventListener_1.EventListener, { passive: true, event: "focusin", handler: this.handlePointerEnter }),
React.createElement(EventListener_1.EventListener, { passive: true, event: "mouseout", handler: this.handlePointerLeave }),
React.createElement(EventListener_1.EventListener, { passive: true, event: "focusout", handler: this.handlePointerLeave }))) : null;
return (React.createElement(React.Fragment, null,
React.createElement(EventListener_1.EventListener, { passive: true, event: "mousedown", handler: this.handlePressStart }),
React.createElement(EventListener_1.EventListener, { passive: true, event: "touchstart", handler: this.handlePressStart }),
expensiveListeners,
preloadMarkup));
};
ConnectedPrefetcher.prototype.clearTimeout = function () {
if (this.timeout != null) {
clearTimeout(this.timeout);
this.timeout = undefined;
this.timeoutUrl = undefined;
}
};
return ConnectedPrefetcher;
}(React.PureComponent));
function Prefetcher(props) {
return (React.createElement(prefetch_1.PrefetchContext.Consumer, null, function (manager) { return React.createElement(ConnectedPrefetcher, tslib_1.__assign({}, props, { manager: manager })); }));
}
exports.Prefetcher = Prefetcher;
function shouldPrefetchAggressively() {
return (typeof navigator === 'undefined' ||
!('connection' in navigator) ||
!navigator.connection.saveData);
}
function urlsEqual(first, second) {
return ((first == null && first === second) ||
(first != null && second != null && first.href === second.href));
}
function findMatches(records, url) {
return tslib_1.__spread(records).filter(function (_a) {
var match = _a.path;
return matches(url, match);
});
}
function matches(url, matcher) {
return typeof matcher === 'string'
? matcher === url.pathname
: matcher.test(url.pathname);
}
function closestUrlFromNode(element) {
if (!(element instanceof HTMLElement)) {
return undefined;
}
// data-href is a hack for resource list doing the <a> as a sibling
var closestUrl = element.closest('[href], [data-href]');
if (closestUrl == null || !(closestUrl instanceof HTMLElement)) {
return undefined;
}
var url = closestUrl.getAttribute('href') || closestUrl.getAttribute('data-href');
try {
return url ? new URL(url, window.location.href) : undefined;
}
catch (error) {
return undefined;
}
}