@reach/router
Version:
Next generation Routing for React.
183 lines (158 loc) • 5.76 kB
JavaScript
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 getLocation = function getLocation(source) {
var _source$location = source.location,
search = _source$location.search,
hash = _source$location.hash,
href = _source$location.href,
origin = _source$location.origin,
protocol = _source$location.protocol,
host = _source$location.host,
hostname = _source$location.hostname,
port = _source$location.port;
var pathname = source.location.pathname;
if (!pathname && href && canUseDOM) {
var url = new URL(href);
pathname = url.pathname;
}
return {
pathname: encodeURI(decodeURI(pathname)),
search: search,
hash: hash,
href: href,
origin: origin,
protocol: protocol,
host: host,
hostname: hostname,
port: port,
state: source.history.state,
key: source.history.state && source.history.state.key || "initial"
};
};
var createHistory = function createHistory(source, options) {
var listeners = [];
var location = getLocation(source);
var transitioning = false;
var resolveTransition = function resolveTransition() {};
return {
get location() {
return location;
},
get transitioning() {
return transitioning;
},
_onTransitionComplete: function _onTransitionComplete() {
transitioning = false;
resolveTransition();
},
listen: function listen(listener) {
listeners.push(listener);
var popstateListener = function popstateListener() {
location = getLocation(source);
listener({ location: location, action: "POP" });
};
source.addEventListener("popstate", popstateListener);
return function () {
source.removeEventListener("popstate", popstateListener);
listeners = listeners.filter(function (fn) {
return fn !== listener;
});
};
},
navigate: function navigate(to) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
state = _ref.state,
_ref$replace = _ref.replace,
replace = _ref$replace === undefined ? false : _ref$replace;
if (typeof to === "number") {
source.history.go(to);
} else {
state = _extends({}, state, { key: Date.now() + "" });
// try...catch iOS Safari limits to 100 pushState calls
try {
if (transitioning || replace) {
source.history.replaceState(state, null, to);
} else {
source.history.pushState(state, null, to);
}
} catch (e) {
source.location[replace ? "replace" : "assign"](to);
}
}
location = getLocation(source);
transitioning = true;
var transition = new Promise(function (res) {
return resolveTransition = res;
});
listeners.forEach(function (listener) {
return listener({ location: location, action: "PUSH" });
});
return transition;
}
};
};
////////////////////////////////////////////////////////////////////////////////
// Stores history entries in memory for testing or other platforms like Native
var createMemorySource = function createMemorySource() {
var initialPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "/";
var searchIndex = initialPath.indexOf("?");
var initialLocation = {
pathname: searchIndex > -1 ? initialPath.substr(0, searchIndex) : initialPath,
search: searchIndex > -1 ? initialPath.substr(searchIndex) : ""
};
var index = 0;
var stack = [initialLocation];
var states = [null];
return {
get location() {
return stack[index];
},
addEventListener: function addEventListener(name, fn) {},
removeEventListener: function removeEventListener(name, fn) {},
history: {
get entries() {
return stack;
},
get index() {
return index;
},
get state() {
return states[index];
},
pushState: function pushState(state, _, uri) {
var _uri$split = uri.split("?"),
pathname = _uri$split[0],
_uri$split$ = _uri$split[1],
search = _uri$split$ === undefined ? "" : _uri$split$;
index++;
stack.push({ pathname: pathname, search: search.length ? "?" + search : search });
states.push(state);
},
replaceState: function replaceState(state, _, uri) {
var _uri$split2 = uri.split("?"),
pathname = _uri$split2[0],
_uri$split2$ = _uri$split2[1],
search = _uri$split2$ === undefined ? "" : _uri$split2$;
stack[index] = { pathname: pathname, search: search };
states[index] = state;
},
go: function go(to) {
var newIndex = index + to;
if (newIndex < 0 || newIndex > states.length - 1) {
return;
}
index = newIndex;
}
}
};
};
////////////////////////////////////////////////////////////////////////////////
// global history - uses window.history as the source if available, otherwise a
// memory history
var canUseDOM = !!(typeof window !== "undefined" && window.document && window.document.createElement);
var getSource = function getSource() {
return canUseDOM ? window : createMemorySource();
};
var globalHistory = createHistory(getSource());
var navigate = globalHistory.navigate;
////////////////////////////////////////////////////////////////////////////////
export { globalHistory, navigate, createHistory, createMemorySource };