Files
old-kitabcitab-frontend/kitabcitab/node_modules/next/dist/client/components/layout-router.js
2022-12-27 12:05:56 +01:00

372 lines
18 KiB
JavaScript

"use client";
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = OuterLayoutRouter;
exports.InnerLayoutRouter = InnerLayoutRouter;
var _extends = require("@swc/helpers/lib/_extends.js").default;
var _interop_require_default = require("@swc/helpers/lib/_interop_require_default.js").default;
var _interop_require_wildcard = require("@swc/helpers/lib/_interop_require_wildcard.js").default;
var _react = _interop_require_wildcard(require("react"));
var _reactDom = _interop_require_default(require("react-dom"));
var _appRouterContext = require("../../shared/lib/app-router-context");
var _appRouter = require("./app-router");
var _infinitePromise = require("./infinite-promise");
var _errorBoundary = require("./error-boundary");
var _matchSegments = require("./match-segments");
var _navigation = require("./navigation");
function OuterLayoutRouter({ parallelRouterKey , segmentPath , childProp , error , errorStyles , templateStyles , loading , loadingStyles , hasLoading , template , notFound , notFoundStyles , rootLayoutIncluded }) {
const context = (0, _react).useContext(_appRouterContext.LayoutRouterContext);
if (!context) {
throw new Error('invariant expected layout router to be mounted');
}
const { childNodes , tree , url } = context;
// Get the current parallelRouter cache node
let childNodesForParallelRouter = childNodes.get(parallelRouterKey);
// If the parallel router cache node does not exist yet, create it.
// This writes to the cache when there is no item in the cache yet. It never *overwrites* existing cache items which is why it's safe in concurrent mode.
if (!childNodesForParallelRouter) {
childNodes.set(parallelRouterKey, new Map());
childNodesForParallelRouter = childNodes.get(parallelRouterKey);
}
// Get the active segment in the tree
// The reason arrays are used in the data format is that these are transferred from the server to the browser so it's optimized to save bytes.
const treeSegment = tree[1][parallelRouterKey][0];
const childPropSegment = Array.isArray(childProp.segment) ? childProp.segment[1] : childProp.segment;
// If segment is an array it's a dynamic route and we want to read the dynamic route value as the segment to get from the cache.
const currentChildSegment = Array.isArray(treeSegment) ? treeSegment[1] : treeSegment;
/**
* Decides which segments to keep rendering, all segments that are not active will be wrapped in `<Offscreen>`.
*/ // TODO-APP: Add handling of `<Offscreen>` when it's available.
const preservedSegments = [
currentChildSegment
];
return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, preservedSegments.map((preservedSegment)=>{
return(/*
- Error boundary
- Only renders error boundary if error component is provided.
- Rendered for each segment to ensure they have their own error state.
- Loading boundary
- Only renders suspense boundary if loading components is provided.
- Rendered for each segment to ensure they have their own loading state.
- Passed to the router during rendering to ensure it can be immediately rendered when suspending on a Flight fetch.
*/ /*#__PURE__*/ _react.default.createElement(_appRouterContext.TemplateContext.Provider, {
key: preservedSegment,
value: /*#__PURE__*/ _react.default.createElement(_errorBoundary.ErrorBoundary, {
errorComponent: error,
errorStyles: errorStyles
}, /*#__PURE__*/ _react.default.createElement(LoadingBoundary, {
hasLoading: hasLoading,
loading: loading,
loadingStyles: loadingStyles
}, /*#__PURE__*/ _react.default.createElement(NotFoundBoundary, {
notFound: notFound,
notFoundStyles: notFoundStyles
}, /*#__PURE__*/ _react.default.createElement(RedirectBoundary, null, /*#__PURE__*/ _react.default.createElement(InnerLayoutRouter, {
parallelRouterKey: parallelRouterKey,
url: url,
tree: tree,
childNodes: childNodesForParallelRouter,
childProp: childPropSegment === preservedSegment ? childProp : null,
segmentPath: segmentPath,
path: preservedSegment,
isActive: currentChildSegment === preservedSegment,
rootLayoutIncluded: rootLayoutIncluded
})))))
}, /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, templateStyles, template)));
}));
}
/**
* Add refetch marker to router state at the point of the current layout segment.
* This ensures the response returned is not further down than the current layout segment.
*/ function walkAddRefetch(segmentPathToWalk, treeToRecreate) {
if (segmentPathToWalk) {
const [segment, parallelRouteKey] = segmentPathToWalk;
const isLast = segmentPathToWalk.length === 2;
if ((0, _matchSegments).matchSegment(treeToRecreate[0], segment)) {
if (treeToRecreate[1].hasOwnProperty(parallelRouteKey)) {
if (isLast) {
const subTree = walkAddRefetch(undefined, treeToRecreate[1][parallelRouteKey]);
return [
treeToRecreate[0],
_extends({}, treeToRecreate[1], {
[parallelRouteKey]: [
subTree[0],
subTree[1],
subTree[2],
'refetch',
]
}),
];
}
return [
treeToRecreate[0],
_extends({}, treeToRecreate[1], {
[parallelRouteKey]: walkAddRefetch(segmentPathToWalk.slice(2), treeToRecreate[1][parallelRouteKey])
}),
];
}
}
}
return treeToRecreate;
}
// TODO-APP: Replace with new React API for finding dom nodes without a `ref` when available
/**
* Wraps ReactDOM.findDOMNode with additional logic to hide React Strict Mode warning
*/ function findDOMNode(instance) {
// Tree-shake for server bundle
if (typeof window === undefined) return null;
// Only apply strict mode warning when not in production
if (process.env.NODE_ENV !== 'production') {
const originalConsoleError = console.error;
try {
console.error = (...messages)=>{
// Ignore strict mode warning for the findDomNode call below
if (!messages[0].includes('Warning: %s is deprecated in StrictMode.')) {
originalConsoleError(...messages);
}
};
return _reactDom.default.findDOMNode(instance);
} finally{
console.error = originalConsoleError;
}
}
return _reactDom.default.findDOMNode(instance);
}
/**
* Check if the top of the HTMLElement is in the viewport.
*/ function topOfElementInViewport(element) {
const rect = element.getBoundingClientRect();
return rect.top >= 0;
}
class ScrollAndFocusHandler extends _react.default.Component {
componentDidMount() {
// Handle scroll and focus, it's only applied once in the first useEffect that triggers that changed.
const { focusAndScrollRef } = this.props;
const domNode = findDOMNode(this);
if (focusAndScrollRef.apply && domNode instanceof HTMLElement) {
// State is mutated to ensure that the focus and scroll is applied only once.
focusAndScrollRef.apply = false;
// Set focus on the element
domNode.focus();
// Only scroll into viewport when the layout is not visible currently.
if (!topOfElementInViewport(domNode)) {
const htmlElement = document.documentElement;
const existing = htmlElement.style.scrollBehavior;
htmlElement.style.scrollBehavior = 'auto';
// In Chrome-based browsers we need to force reflow before calling `scrollTo`.
// Otherwise it will not pickup the change in scrollBehavior
// More info here: https://github.com/vercel/next.js/issues/40719#issuecomment-1336248042
htmlElement.getClientRects();
domNode.scrollIntoView();
htmlElement.style.scrollBehavior = existing;
}
}
}
render() {
return this.props.children;
}
}
function InnerLayoutRouter({ parallelRouterKey , url , childNodes , childProp , segmentPath , tree , // TODO-APP: implement `<Offscreen>` when available.
// isActive,
path , rootLayoutIncluded }) {
const context = (0, _react).useContext(_appRouterContext.GlobalLayoutRouterContext);
if (!context) {
throw new Error('invariant global layout router not mounted');
}
const { changeByServerResponse , tree: fullTree , focusAndScrollRef } = context;
// Read segment path from the parallel router cache node.
let childNode = childNodes.get(path);
// If childProp is available this means it's the Flight / SSR case.
if (childProp && // TODO-APP: verify if this can be null based on user code
childProp.current !== null) {
if (childNode && childNode.status === _appRouterContext.CacheStates.LAZY_INITIALIZED) {
// @ts-expect-error TODO-APP: handle changing of the type
childNode.status = _appRouterContext.CacheStates.READY;
// @ts-expect-error TODO-APP: handle changing of the type
childNode.subTreeData = childProp.current;
// Mutates the prop in order to clean up the memory associated with the subTreeData as it is now part of the cache.
childProp.current = null;
} else {
// Add the segment's subTreeData to the cache.
// This writes to the cache when there is no item in the cache yet. It never *overwrites* existing cache items which is why it's safe in concurrent mode.
childNodes.set(path, {
status: _appRouterContext.CacheStates.READY,
data: null,
subTreeData: childProp.current,
parallelRoutes: new Map()
});
// Mutates the prop in order to clean up the memory associated with the subTreeData as it is now part of the cache.
childProp.current = null;
// In the above case childNode was set on childNodes, so we have to get it from the cacheNodes again.
childNode = childNodes.get(path);
}
}
// When childNode is not available during rendering client-side we need to fetch it from the server.
if (!childNode || childNode.status === _appRouterContext.CacheStates.LAZY_INITIALIZED) {
/**
* Router state with refetch marker added
*/ // TODO-APP: remove ''
const refetchTree = walkAddRefetch([
'',
...segmentPath
], fullTree);
/**
* Flight data fetch kicked off during render and put into the cache.
*/ childNodes.set(path, {
status: _appRouterContext.CacheStates.DATA_FETCH,
data: (0, _appRouter).fetchServerResponse(new URL(url, location.origin), refetchTree),
subTreeData: null,
head: childNode && childNode.status === _appRouterContext.CacheStates.LAZY_INITIALIZED ? childNode.head : undefined,
parallelRoutes: childNode && childNode.status === _appRouterContext.CacheStates.LAZY_INITIALIZED ? childNode.parallelRoutes : new Map()
});
// In the above case childNode was set on childNodes, so we have to get it from the cacheNodes again.
childNode = childNodes.get(path);
}
// This case should never happen so it throws an error. It indicates there's a bug in the Next.js.
if (!childNode) {
throw new Error('Child node should always exist');
}
// This case should never happen so it throws an error. It indicates there's a bug in the Next.js.
if (childNode.subTreeData && childNode.data) {
throw new Error('Child node should not have both subTreeData and data');
}
// If cache node has a data request we have to unwrap response by `use` and update the cache.
if (childNode.data) {
/**
* Flight response data
*/ // When the data has not resolved yet `use` will suspend here.
const [flightData, overrideCanonicalUrl] = (0, _react).use(childNode.data);
// Handle case when navigating to page in `pages` from `app`
if (typeof flightData === 'string') {
window.location.href = url;
return null;
}
// segmentPath from the server does not match the layout's segmentPath
childNode.data = null;
// setTimeout is used to start a new transition during render, this is an intentional hack around React.
setTimeout(()=>{
// @ts-ignore startTransition exists
_react.default.startTransition(()=>{
changeByServerResponse(fullTree, flightData, overrideCanonicalUrl);
});
});
// Suspend infinitely as `changeByServerResponse` will cause a different part of the tree to be rendered.
(0, _react).use((0, _infinitePromise).createInfinitePromise());
}
// If cache node has no subTreeData and no data request we have to infinitely suspend as the data will likely flow in from another place.
// TODO-APP: double check users can't return null in a component that will kick in here.
if (!childNode.subTreeData) {
(0, _react).use((0, _infinitePromise).createInfinitePromise());
}
const subtree = // The layout router context narrows down tree and childNodes at each level.
/*#__PURE__*/ _react.default.createElement(_appRouterContext.LayoutRouterContext.Provider, {
value: {
tree: tree[1][parallelRouterKey],
childNodes: childNode.parallelRoutes,
// TODO-APP: overriding of url for parallel routes
url: url
}
}, childNode.subTreeData);
// Ensure root layout is not wrapped in a div as the root layout renders `<html>`
return rootLayoutIncluded ? /*#__PURE__*/ _react.default.createElement(ScrollAndFocusHandler, {
focusAndScrollRef: focusAndScrollRef
}, subtree) : subtree;
}
/**
* Renders suspense boundary with the provided "loading" property as the fallback.
* If no loading property is provided it renders the children without a suspense boundary.
*/ function LoadingBoundary({ children , loading , loadingStyles , hasLoading }) {
if (hasLoading) {
return /*#__PURE__*/ _react.default.createElement(_react.default.Suspense, {
fallback: /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, loadingStyles, loading)
}, children);
}
return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, children);
}
function HandleRedirect({ redirect }) {
const router = (0, _navigation).useRouter();
(0, _react).useEffect(()=>{
router.replace(redirect, {});
}, [
redirect,
router
]);
return null;
}
class RedirectErrorBoundary extends _react.default.Component {
static getDerivedStateFromError(error) {
var ref;
if (error == null ? void 0 : (ref = error.digest) == null ? void 0 : ref.startsWith('NEXT_REDIRECT')) {
const url = error.digest.split(';')[1];
return {
redirect: url
};
}
// Re-throw if error is not for redirect
throw error;
}
render() {
const redirect = this.state.redirect;
if (redirect !== null) {
return /*#__PURE__*/ _react.default.createElement(HandleRedirect, {
redirect: redirect
});
}
return this.props.children;
}
constructor(props){
super(props);
this.state = {
redirect: null
};
}
}
function RedirectBoundary({ children }) {
const router = (0, _navigation).useRouter();
return /*#__PURE__*/ _react.default.createElement(RedirectErrorBoundary, {
router: router
}, children);
}
class NotFoundErrorBoundary extends _react.default.Component {
static getDerivedStateFromError(error) {
if ((error == null ? void 0 : error.digest) === 'NEXT_NOT_FOUND') {
return {
notFoundTriggered: true
};
}
// Re-throw if error is not for 404
throw error;
}
render() {
if (this.state.notFoundTriggered) {
return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/ _react.default.createElement("meta", {
name: "robots",
content: "noindex"
}), this.props.notFoundStyles, this.props.notFound);
}
return this.props.children;
}
constructor(props){
super(props);
this.state = {
notFoundTriggered: false
};
}
}
function NotFoundBoundary({ notFound , notFoundStyles , children }) {
return notFound ? /*#__PURE__*/ _react.default.createElement(NotFoundErrorBoundary, {
notFound: notFound,
notFoundStyles: notFoundStyles
}, children) : /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, children);
}
if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
Object.defineProperty(exports.default, '__esModule', { value: true });
Object.assign(exports.default, exports);
module.exports = exports.default;
}
//# sourceMappingURL=layout-router.js.map