react-history-switch
Version:
Self-hosted context-free Switch routing component for History.js library (React). The library was created to transfer navigation responsibility from a view into Mobx state container (MVC). Also can be used separately as a self-hosted router
713 lines (602 loc) • 19 kB
JavaScript
var React = require('react');
var history = require('history');
var pathToRegexp = require('path-to-regexp');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () {
return e[k];
}
});
}
});
}
n['default'] = e;
return n;
}
var React__namespace = /*#__PURE__*/_interopNamespace(React);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
function _extends() {
_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;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var Context = React.createContext(history.createMemoryHistory());
var HistoryContext = function HistoryContext(_ref) {
var children = _ref.children,
history = _ref.history;
return React__namespace.createElement(Context.Provider, {
value: history
}, children);
};
var useHistoryContext = function useHistoryContext() {
return React.useContext(Context);
};
var _excluded$1 = ["to"];
var Link = function Link(_ref) {
var to = _ref.to,
otherProps = _objectWithoutPropertiesLoose(_ref, _excluded$1);
var history = useHistoryContext();
return React__namespace.createElement("a", Object.assign({}, otherProps, {
href: '#',
onClick: function onClick() {
return history.push(to);
}
}));
};
var Error = function Error() {
return React__default['default'].createElement("p", null, "500");
};
var queued = function queued(promise) {
var lastPromise = Promise.resolve();
var wrappedFn = function wrappedFn() {
var _arguments = arguments;
lastPromise = lastPromise.then(function () {
return promise.apply(void 0, [].slice.call(_arguments));
})["finally"](function () {
return wrappedFn.clear();
});
return lastPromise;
};
wrappedFn.clear = function () {
lastPromise = Promise.resolve();
};
return wrappedFn;
};
function _catch(body, recover) {
try {
var result = body();
} catch (e) {
return recover(e);
}
if (result && result.then) {
return result.then(void 0, recover);
}
return result;
}
function _finallyRethrows(body, finalizer) {
try {
var result = body();
} catch (e) {
return finalizer(true, e);
}
if (result && result.then) {
return result.then(finalizer.bind(null, false), finalizer.bind(null, true));
}
return finalizer(false, result);
}
var Async = function Async(_ref) {
var children = _ref.children,
_ref$Loader = _ref.Loader,
Loader = _ref$Loader === void 0 ? function () {
return null;
} : _ref$Loader,
_ref$Error = _ref.Error,
Error = _ref$Error === void 0 ? function () {
return null;
} : _ref$Error,
onLoadStart = _ref.onLoadStart,
onLoadEnd = _ref.onLoadEnd,
payload = _ref.payload,
_ref$deps = _ref.deps,
deps = _ref$deps === void 0 ? [] : _ref$deps;
var _useState = React.useState(''),
child = _useState[0],
setChild = _useState[1];
var _useState2 = React.useState(false),
loading = _useState2[0],
setLoading = _useState2[1];
var _useState3 = React.useState(false),
error = _useState3[0],
setError = _useState3[1];
var execute = React.useMemo(function () {
return queued(function (payload) {
try {
var _exit2;
var isOk = true;
setLoading(true);
setError(false);
onLoadStart && onLoadStart();
var _temp2 = _finallyRethrows(function () {
return _catch(function () {
var result = children(payload);
if (result instanceof Promise) {
_exit2 = 1;
return Promise.resolve(result).then(function (_result2) {
return _result2 || null;
});
} else {
_exit2 = 1;
return result || null;
}
}, function () {
isOk = false;
});
}, function (_wasThrown, _result) {
setLoading(false);
setError(!isOk);
onLoadEnd && onLoadEnd(isOk);
if (_wasThrown) throw _result;
return _result;
});
return Promise.resolve(_temp2 && _temp2.then ? _temp2.then(function (_result) {
return _exit2 ? _result : null;
}) : _exit2 ? _temp2 : null);
} catch (e) {
return Promise.reject(e);
}
});
}, []);
React.useEffect(function () {
var process = function process() {
try {
return Promise.resolve(execute(payload)).then(function (result) {
setChild(result);
});
} catch (e) {
return Promise.reject(e);
}
};
process();
}, [payload].concat(deps));
if (loading) {
return React__namespace.createElement(Loader, null);
} else if (error) {
return React__namespace.createElement(Error, null);
} else {
return React__namespace.createElement(React__namespace.Fragment, null, child);
}
};
var Loader = function Loader() {
return React__default['default'].createElement("p", null, "Loading");
};
var _excluded = ["Loader", "Error", "onLoadEnd", "onLoadStart", "children", "state", "payload"];
var FetchView = function FetchView(_ref) {
var _ref$Loader = _ref.Loader,
Loader$1 = _ref$Loader === void 0 ? Loader : _ref$Loader,
_ref$Error = _ref.Error,
Error$1 = _ref$Error === void 0 ? Error : _ref$Error,
onLoadEnd = _ref.onLoadEnd,
onLoadStart = _ref.onLoadStart,
children = _ref.children,
state = _ref.state,
payload = _ref.payload,
otherProps = _objectWithoutPropertiesLoose(_ref, _excluded);
var handleData = function handleData(payload) {
try {
if (Array.isArray(state)) {
return Promise.resolve(Promise.all(state.map(function (item) {
return item(payload);
})));
} else {
return Promise.resolve(state(payload)).then(function (_state) {
return [_state];
});
}
} catch (e) {
return Promise.reject(e);
}
};
return React__default['default'].createElement(Async, Object.assign({}, otherProps, {
Loader: Loader$1,
Error: Error$1,
onLoadStart: onLoadStart,
onLoadEnd: onLoadEnd,
payload: payload
}), function (payload) {
try {
return Promise.resolve(handleData(payload)).then(function (data) {
return children.apply(void 0, data);
});
} catch (e) {
return Promise.reject(e);
}
});
};
var Forbidden = function Forbidden() {
return React__default['default'].createElement("p", null, "Forbidden");
};
var NotFound = function NotFound() {
return React__default['default'].createElement("p", null, "Not found");
};
var createWindowHistory = function createWindowHistory() {
if (window.location.protocol === 'file:') {
return history.createMemoryHistory();
} else {
return history.createBrowserHistory();
}
};
var sleep = function sleep(timeout) {
if (timeout === void 0) {
timeout = 1000;
}
return new Promise(function (resolve) {
return setTimeout(function () {
return resolve();
}, timeout);
});
};
var _iteratorSymbol = typeof Symbol !== "undefined" ? Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator")) : "@@iterator";
function _settle(pact, state, value) {
if (!pact.s) {
if (value instanceof _Pact) {
if (value.s) {
if (state & 1) {
state = value.s;
}
value = value.v;
} else {
value.o = _settle.bind(null, pact, state);
return;
}
}
if (value && value.then) {
value.then(_settle.bind(null, pact, state), _settle.bind(null, pact, 2));
return;
}
pact.s = state;
pact.v = value;
var observer = pact.o;
if (observer) {
observer(pact);
}
}
}
var _Pact = /*#__PURE__*/function () {
function _Pact() {}
_Pact.prototype.then = function (onFulfilled, onRejected) {
var result = new _Pact();
var state = this.s;
if (state) {
var callback = state & 1 ? onFulfilled : onRejected;
if (callback) {
try {
_settle(result, 1, callback(this.v));
} catch (e) {
_settle(result, 2, e);
}
return result;
} else {
return this;
}
}
this.o = function (_this) {
try {
var value = _this.v;
if (_this.s & 1) {
_settle(result, 1, onFulfilled ? onFulfilled(value) : value);
} else if (onRejected) {
_settle(result, 1, onRejected(value));
} else {
_settle(result, 2, value);
}
} catch (e) {
_settle(result, 2, e);
}
};
return result;
};
return _Pact;
}();
function _isSettledPact(thenable) {
return thenable instanceof _Pact && thenable.s & 1;
}
function _forTo(array, body, check) {
var i = -1,
pact,
reject;
function _cycle(result) {
try {
while (++i < array.length && (!check || !check())) {
result = body(i);
if (result && result.then) {
if (_isSettledPact(result)) {
result = result.v;
} else {
result.then(_cycle, reject || (reject = _settle.bind(null, pact = new _Pact(), 2)));
return;
}
}
}
if (pact) {
_settle(pact, 1, result);
} else {
pact = result;
}
} catch (e) {
_settle(pact || (pact = new _Pact()), 2, e);
}
}
_cycle();
return pact;
}
var canActivate = function canActivate(item) {
try {
var _item$guard = item.guard,
guard = _item$guard === void 0 ? function () {
return true;
} : _item$guard;
var isAvailable = guard();
if (isAvailable instanceof Promise) {
return Promise.resolve(isAvailable);
} else {
return Promise.resolve(isAvailable);
}
} catch (e) {
return Promise.reject(e);
}
};
function _forOf(target, body, check) {
if (typeof target[_iteratorSymbol] === "function") {
var _cycle = function _cycle(result) {
try {
while (!(step = iterator.next()).done && (!check || !check())) {
result = body(step.value);
if (result && result.then) {
if (_isSettledPact(result)) {
result = result.v;
} else {
result.then(_cycle, reject || (reject = _settle.bind(null, pact = new _Pact(), 2)));
return;
}
}
}
if (pact) {
_settle(pact, 1, result);
} else {
pact = result;
}
} catch (e) {
_settle(pact || (pact = new _Pact()), 2, e);
}
};
var iterator = target[_iteratorSymbol](),
step,
pact,
reject;
_cycle();
if (iterator["return"]) {
var _fixup = function _fixup(value) {
try {
if (!step.done) {
iterator["return"]();
}
} catch (e) {}
return value;
};
if (pact && pact.then) {
return pact.then(_fixup, function (e) {
throw _fixup(e);
});
}
_fixup();
}
return pact;
} // No support for Symbol.iterator
// No support for Symbol.iterator
if (!("length" in target)) {
throw new TypeError("Object is not iterable");
} // Handle live collections properly
// Handle live collections properly
var values = [];
for (var i = 0; i < target.length; i++) {
values.push(target[i]);
}
return _forTo(values, function (i) {
return body(values[i]);
}, check);
}
var DEFAULT_HISTORY = createWindowHistory();
var Fragment = function Fragment() {
return React__default['default'].createElement(React__default['default'].Fragment, null);
};
var Switch = function Switch(_ref) {
var _ref$Loader = _ref.Loader,
Loader$1 = _ref$Loader === void 0 ? Loader : _ref$Loader,
_ref$Forbidden = _ref.Forbidden,
Forbidden$1 = _ref$Forbidden === void 0 ? Forbidden : _ref$Forbidden,
_ref$NotFound = _ref.NotFound,
NotFound$1 = _ref$NotFound === void 0 ? NotFound : _ref$NotFound,
_ref$Error = _ref.Error,
Error$1 = _ref$Error === void 0 ? Error : _ref$Error,
_ref$history = _ref.history,
history = _ref$history === void 0 ? DEFAULT_HISTORY : _ref$history,
items = _ref.items,
onLoadStart = _ref.onLoadStart,
onLoadEnd = _ref.onLoadEnd;
var unloadRef = React.useRef(null);
var _useState = React.useState(_extends({}, history.location)),
location = _useState[0],
setLocation = _useState[1];
React.useEffect(function () {
var handleLocation = function handleLocation(update) {
if (update.location.pathname !== location.pathname) {
var newLocation = _extends({}, update.location);
setLocation(newLocation);
}
};
return history.listen(handleLocation);
}, [history, location]);
var handleState = React.useMemo(function () {
return function (url) {
try {
var _temp8 = function _temp8(_unloadRef$current) {
var _exit;
function _temp5(_result3) {
return _exit ? _result3 : {
element: NotFound$1
};
}
_unloadRef$current;
var _temp4 = _forOf(items, function (item) {
var _item$element = item.element,
element = _item$element === void 0 ? Fragment : _item$element,
redirect = item.redirect,
prefetch = item.prefetch,
unload = item.unload,
path = item.path;
var params = {};
var keys = [];
var reg = pathToRegexp.pathToRegexp(path, keys);
var match = reg.test(url);
var buildParams = function buildParams() {
var tokens = reg.exec(url);
tokens && keys.forEach(function (key, i) {
params[key.name] = tokens[i + 1];
});
};
var provideUnloadRef = function provideUnloadRef() {
if (unload) {
unloadRef.current = function () {
try {
return Promise.resolve(Promise.resolve(unload(params))).then(function () {
unloadRef.current = null;
});
} catch (e) {
return Promise.reject(e);
}
};
}
};
return function () {
if (match) {
var _exit4;
return Promise.resolve(canActivate(item)).then(function (_canActivate) {
var _exit3;
function _temp3(_result2) {
if (_exit3) ;
_exit = 1;
return {
element: Forbidden$1
};
}
var _temp2 = function () {
if (_canActivate) {
var _temp7 = function _temp7(_prefetch) {
prefetch && Object.assign(params, _prefetch);
provideUnloadRef();
if (typeof redirect === 'string') {
setLocation(function (location) {
return _extends({}, location, {
pathname: redirect
});
});
_exit = 1;
return {
element: Fragment
};
}
if (typeof redirect === 'function') {
var result = redirect(params);
if (result !== null) {
setLocation(function (location) {
return _extends({}, location, {
pathname: result
});
});
_exit = 1;
return {
element: Fragment
};
}
}
_exit = 1;
return {
element: element,
params: params
};
};
buildParams();
return prefetch ? Promise.resolve(prefetch(params)).then(_temp7) : _temp7(prefetch);
}
}();
return _temp2 && _temp2.then ? _temp2.then(_temp3) : _temp3(_temp2);
});
}
}();
}, function () {
return _exit;
});
return _temp4 && _temp4.then ? _temp4.then(_temp5) : _temp5(_temp4);
};
var _unloadRef$current3 = unloadRef.current;
return Promise.resolve(_unloadRef$current3 ? Promise.resolve(unloadRef.current()).then(_temp8) : _temp8(_unloadRef$current3));
} catch (e) {
return Promise.reject(e);
}
};
}, [location]);
return React__default['default'].createElement(HistoryContext, {
history: history
}, React__default['default'].createElement(FetchView, {
state: handleState,
Loader: Loader$1,
Error: Error$1,
payload: location.pathname,
onLoadStart: onLoadStart,
onLoadEnd: onLoadEnd
}, function (data) {
try {
var _data$element = data.element,
Element = _data$element === void 0 ? Fragment : _data$element,
params = data.params;
/* delay to prevent sync execution for appear animation */
return Promise.resolve(sleep(0)).then(function () {
return React__default['default'].createElement(Element, Object.assign({}, params));
});
} catch (e) {
return Promise.reject(e);
}
}));
};
exports.Link = Link;
exports.Switch = Switch;
//# sourceMappingURL=index.js.map