UNPKG

react-navi

Version:

A batteries-included router for react.

147 lines 6.76 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var React = __importStar(require("react")); var HashScroll_1 = require("./HashScroll"); var NaviContext_1 = require("./NaviContext"); var ViewHeadRendererContext_1 = require("./ViewHeadRendererContext"); function defaultUseViewChunkPredicate(chunk) { return chunk.type === 'view'; } function useViewElement(options) { if (options === void 0) { options = {}; } var result = useView(options); return result && result.element; } exports.useViewElement = useViewElement; function useView(_a) { var _b = _a === void 0 ? {} : _a, _c = _b.disableScrolling, disableScrolling = _c === void 0 ? false : _c, hashScrollBehavior = _b.hashScrollBehavior, renderHead = _b.renderHead, _d = _b.where, where = _d === void 0 ? defaultUseViewChunkPredicate : _d; var hashScrollBehaviorFromContext = React.useContext(HashScroll_1.HashScrollContext); var renderHeadFromContext = React.useContext(ViewHeadRendererContext_1.ViewHeadRendererContext); var context = React.useContext(NaviContext_1.NaviContext); if (hashScrollBehavior === undefined) { hashScrollBehavior = hashScrollBehaviorFromContext; } if (renderHead === undefined && renderHeadFromContext) { renderHead = renderHeadFromContext; } var route = context.steadyRoute || context.busyRoute; if (!route) { throw new Error('react-navi: A <View> component cannot be rendered outside of a <Router> or <NaviProvider> component.'); } var unconsumedChunks = context.unconsumedSteadyRouteChunks || route.chunks; var index = unconsumedChunks.findIndex(where); var view = index !== -1 && unconsumedChunks[index].view; // Find any other chunks that come before this chunk, or after this one if // this is the final view chunk. // // Don't treat this as the final chunk is there is an error, as that means // we don't know whether this is really meant to be the final chunk, and we // don't want to throw an error before rendering whatever views we can. var final = index === -1 || (!unconsumedChunks.slice(index + 1).find(where) && route.type !== 'error'); var chunks = React.useMemo(function () { return (final ? unconsumedChunks : unconsumedChunks.slice(0, index + 1)); }, [final, unconsumedChunks, index]); // Look for an error amongst any route chunks that haven't already been used // by a `useView()` and throw it. var errorChunk = chunks.find(function (chunk) { return chunk.type === 'error'; }); if (errorChunk) { throw errorChunk.error || new Error('Unknown routing error'); } // If there's no steady route, then we'll need to wait until a steady // route becomes available using Supsense. if (!view && !context.steadyRoute) { throw context.navigation.getRoute(); } var childContext = React.useMemo(function () { return (__assign(__assign({}, context), { unconsumedSteadyRouteChunks: final ? [] : unconsumedChunks.slice(index + 1) })); }, [context, unconsumedChunks, index]); var connect = React.useCallback(function (children) { return (React.createElement(NaviContext_1.NaviContext.Provider, { value: childContext }, // Clone the content to force a re-render even if content hasn't // changed, as Provider is a PureComponent. React.isValidElement(children) ? React.cloneElement(children) : children)); }, [childContext]); var content = React.useMemo(function () { return typeof view === 'function' ? React.createElement(view, { route: context.steadyRoute, }) : view || null; }, [view, context.steadyRoute]); var head = React.useMemo(function () { return (!renderHead ? null : renderHead(chunks)); }, [ renderHead, chunks, ]); // Scroll to hash or top of page if appropriate. var lastRouteRef = React.useRef(); React.useEffect(function () { var nextRoute = route; var prevRoute = lastRouteRef.current; lastRouteRef.current = route; if (final && route && unconsumedChunks.length !== 0) { if (nextRoute && nextRoute.type !== 'busy') { if (prevRoute && nextRoute.url.pathname === prevRoute.url.pathname && nextRoute.url.search === prevRoute.url.search && nextRoute.url.hash === prevRoute.url.hash) { return; } if (!disableScrolling && (!prevRoute || !prevRoute.url || prevRoute.url.hash !== nextRoute.url.hash || prevRoute.url.pathname !== nextRoute.url.pathname)) { HashScroll_1.scrollToHash(nextRoute.url.hash, prevRoute && prevRoute.url && prevRoute.url.pathname === nextRoute.url.pathname ? hashScrollBehavior : 'auto'); } } } }, [route]); var result = React.useMemo(function () { return ({ chunks: chunks, connect: connect, content: content, element: connect(React.createElement(React.Fragment, null, head, content)), final: final, head: head, }); }, [chunks, connect, content, final, head]); return unconsumedChunks.length === 0 ? null : result; } exports.useView = useView; exports.View = function View(_a) { var disableScrolling = _a.disableScrolling, hashScrollBehavior = _a.hashScrollBehavior, renderHead = _a.renderHead, where = _a.where; var result = useView({ disableScrolling: disableScrolling, hashScrollBehavior: hashScrollBehavior, renderHead: renderHead, where: where, }); if (!result) { throw new Error('A Navi <View> was not able to find a view to render.'); } return result.element; }; //# sourceMappingURL=View.js.map