UNPKG

moy-router

Version:

Give a solution for moy-dom router management.

218 lines (192 loc) 6.6 kB
/** * moy-router v1.0.6 * (jp) 2018 murakami * @license MIT */ import { compose, prepend, join, map, entries, reduce, split, ifElse, includes, prop, concat, type, Maybe, and, or, assoc, __, path, curry, tap, always, length, dissoc } from 'moy-fp'; import pathToRegExp from 'path-to-regexp'; import { Element } from 'moy-dom'; var slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var stringifyQuery = compose(prepend('?'), join('&'), map(compose(join('='), map(encodeURIComponent))), entries); var parseQuery = compose(reduce(function (query, params) { var _compose = compose(map(decodeURIComponent), split('='))(params), _compose2 = slicedToArray(_compose, 2), key = _compose2[0], value = _compose2[1]; query[key] = value; return query; }, {}), split('&')); var pushQueryAndHash = ifElse(function (queryAndHash, route) { var _queryAndHash$split = queryAndHash.split('#'), _queryAndHash$split2 = slicedToArray(_queryAndHash$split, 2), query = _queryAndHash$split2[0], hash = _queryAndHash$split2[1]; route.query = query ? parseQuery(query) : undefined; route.hash = hash; })(function (queryAndHash, route) { return route.query = parseQuery(queryAndHash); })(includes('#')); var handleStringPathname = function handleStringPathname(pathname) { var route = {}; route.pathname = pathname; var queryAndHash = compose(prop(1), split('?'))(pathname); !queryAndHash && pathname.includes('#') && (queryAndHash = compose(prepend('#'), prop(1), split('#'))(pathname)); queryAndHash && pushQueryAndHash(queryAndHash, route); return route; }; var handleObjectPathname = function handleObjectPathname(route) { if (route.params) { route.pathname = pathToRegExp.compile(route.pathname)(route.params); } if (route.query) { route.pathname += stringifyQuery(route.query); } if (route.hash) { route.pathname += concat(route.hash)('#'); } return route; }; var parseRoute = ifElse(handleStringPathname)(handleObjectPathname)(type('String')); var windowMonad = Maybe.of(window); var createHistory = (function (current) { return and(windowMonad.map(function (window) { return window.addEventListener('popstate', compose(assoc('route', __, current), path(['state', 'route']))); }))({ back: function back() { windowMonad.map(function (window) { return window.history.back(); }); }, go: function go(index) { windowMonad.map(function (window) { return window.history.go(index); }); }, forward: function forward() { windowMonad.map(function (window) { return window.history.forward(); }); }, replace: function replace(routeConfig) { var route = parseRoute(routeConfig); windowMonad.map(function (window) { return or(window.history.replaceState(route, '', route.pathname))(assoc('route', route, current)); }); }, push: function push(routeConfig) { var route = parseRoute(routeConfig); windowMonad.map(function (window) { return or(window.history.replaceState(route, '', route.pathname))(assoc('route', route, current)); }); } }); }); var RouterView = curry(function (current, routes) { return function (props) { var currentPathname = current.route.pathname.split('?').map(split('#'))[0][0]; var maybeRouteNode = compose(map(function (route) { return route.component(Object.assign({}, props, { route: { pathname: current.route.pathname, params: current.route.params, query: current.route.query, hash: current.route.hash, state: current.route.state } })); }), map(tap(ifElse(function (currentRoute) { var matched = currentPathname.match(currentRoute.pathnameRegExp); current.route.params = {}; currentRoute.paramKeys.forEach(function (key, index) { current.route.params[key.name] = decodeURIComponent(matched[index + 1]); }); })(always(undefined))(compose(and(!current.route.params), length, prop('paramKeys'))))), Maybe.of)(routes.find(function (route) { return route.pathnameRegExp.test(currentPathname); })); return maybeRouteNode.isJust ? maybeRouteNode.join() : ''; }; }); var RouterLink = curry(function (push, _ref) { var to = _ref.to, innerNode = _ref.innerNode; return Element.of('a', { href: type('String', to) ? to : to.pathname, onclick: function onclick(e) { e.preventDefault(); push(to); } }, innerNode); }); var getLocation = (function () { return Maybe.of(window).map(function (window) { return window.location.pathname + window.location.search + window.location.hash; }); }); var createRouter = (function (routes, subscription) { var routesRegExpPathname = map(compose(dissoc('pathname'), function (route) { return assoc('pathnameRegExp')(pathToRegExp(prop('pathname', route), prop('paramKeys', route), { sensitive: true }))(route); }, tap(function (route) { return route.paramKeys = []; })))(routes); var currentRoute = getLocation().chain(parseRoute); var current = new Proxy({ route: currentRoute }, { set: function set(target, prop$$1, value) { Reflect.set(target, prop$$1, value); prop$$1 === 'route' && subscription(); return true; } }); var _createHistory = createHistory(current), back = _createHistory.back, go = _createHistory.go, forward = _createHistory.forward, replace = _createHistory.replace, push = _createHistory.push; var router = { back: back, go: go, forward: forward, replace: replace, push: push, RouterView: RouterView(current, routesRegExpPathname), RouterLink: RouterLink(push) }; return router; }); export { createRouter };