one
Version:
One is a React framework for web, iOS, and Android apps.
146 lines (143 loc) • 6.34 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import React from "react";
import { getContextKey, stripInvisibleSegmentsFromPath } from "../router/matchers.native.js";
import { useContextKey, useRouteNode } from "../router/Route.native.js";
import { registerProtectedRoutes, replace, resolveProtectedHref, routeInfo, unregisterProtectedRoutes } from "../router/router.native.js";
import { useSortedScreens } from "../router/useScreens.native.js";
import { sortRoutesWithInitial } from "../router/sortRoutes.native.js";
import { withStaticProperties } from "../utils/withStaticProperties.native.js";
import { isProtectedElement } from "../views/Protected.native.js";
import { Screen } from "../views/Screen.native.js";
import { StackScreen } from "./stack-utils/StackScreen.native.js";
import { IsWithinNativeNavigator } from "./NativeNavigatorContext.native.js";
function useFilterScreenChildren(children) {
var { isCustomNavigator, contextKey } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] :
/** Used for sending developer hints */
{};
return React.useMemo(function() {
var customChildren = [];
var screens = [];
var protectedScreens = /* @__PURE__ */ new Set();
var guardedRedirects = /* @__PURE__ */ new Map();
function flattenChild(child) {
var exclude = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false, redirectTo = arguments.length > 2 ? arguments[2] : void 0;
if (/* @__PURE__ */ React.isValidElement(child) && (child.type === Screen || child.type === StackScreen)) {
if (typeof child.props === "object" && child.props && "name" in child.props && !child.props.name) {
throw new Error(`<Screen /> component in \`default export\` at \`app${contextKey}/_layout\` must have a \`name\` prop when used as a child of a Layout Route.`);
}
if (process.env.NODE_ENV !== "production") {
if ([
"children",
"component",
"getComponent"
].some(function(key) {
return child.props && typeof child.props === "object" && key in child.props;
})) {
throw new Error(`<Screen /> component in \`default export\` at \`app${contextKey}/_layout\` must not have a \`children\`, \`component\`, or \`getComponent\` prop when used as a child of a Layout Route`);
}
}
var screenProps = child.props;
if (exclude && screenProps.name) {
protectedScreens.add(screenProps.name);
guardedRedirects.set(screenProps.name, redirectTo);
} else {
screens.push(screenProps);
}
return;
}
if (isProtectedElement(child)) {
var guardFails = !child.props.guard;
var excludeChildren = exclude || guardFails;
var childRedirectTo = guardFails ? child.props.redirectTo : redirectTo;
React.Children.forEach(child.props.children, function(nested) {
flattenChild(nested, excludeChildren, childRedirectTo);
});
return;
}
if (isCustomNavigator) {
customChildren.push(child);
} else if (child != null && process.env.NODE_ENV === "development") {
console.warn(`[one] a non-<Screen> child of the navigator at "app${contextKey}/_layout" renders on web only. On native this navigator is drawn by react-navigation and the child is ignored.`);
}
}
React.Children.forEach(children, function(child) {
return flattenChild(child);
});
if (process.env.NODE_ENV !== "production") {
var names = screens.map(function(screen) {
return screen.name;
});
if (names && new Set(names).size !== names.length) {
throw new Error("Screen names must be unique: " + names);
}
}
return {
screens,
children: customChildren,
protectedScreens,
guardedRedirects
};
}, [
children,
contextKey,
isCustomNavigator
]);
}
function useResolvedGuardedRedirects(guardedRedirects) {
var node = useRouteNode();
return React.useMemo(function() {
if (!node) {
return guardedRedirects;
}
var defaultRoute = [...node.children].sort(sortRoutesWithInitial(node.initialRouteName)).find(function(child) {
var normalized = child.route.replace(/\/index$/, "");
return !(guardedRedirects.has(child.route) || guardedRedirects.has(normalized));
});
var defaultHref = defaultRoute ? stripInvisibleSegmentsFromPath(getContextKey(defaultRoute.contextKey)) || "/" : void 0;
return new Map(Array.from(guardedRedirects, function(param) {
var [name, redirectTo] = param;
return [name, redirectTo !== null && redirectTo !== void 0 ? redirectTo : defaultHref];
}));
}, [guardedRedirects, node]);
}
function withLayoutContext(Nav, processor, options) {
return withStaticProperties(/* @__PURE__ */ React.forwardRef(function(propsIn, ref) {
var { children, ...props } = propsIn;
var contextKey = useContextKey();
var { screens, protectedScreens, guardedRedirects } = useFilterScreenChildren(children, { contextKey });
var resolvedGuardedRedirects = useResolvedGuardedRedirects(guardedRedirects);
registerProtectedRoutes(contextKey, resolvedGuardedRedirects);
var currentPathname = routeInfo === null || routeInfo === void 0 ? void 0 : routeInfo.pathname;
var protectedHref = currentPathname ? resolveProtectedHref(currentPathname) : currentPathname;
React.useEffect(function() {
registerProtectedRoutes(contextKey, resolvedGuardedRedirects);
return function() {
unregisterProtectedRoutes(contextKey);
};
}, [contextKey, resolvedGuardedRedirects]);
React.useEffect(function() {
if (currentPathname && protectedHref && protectedHref !== currentPathname) {
replace(protectedHref);
}
}, [currentPathname, protectedHref]);
var processed = processor ? processor(screens !== null && screens !== void 0 ? screens : []) : screens;
var sorted = useSortedScreens(processed !== null && processed !== void 0 ? processed : [], {
remaining: (options === null || options === void 0 ? void 0 : options.undeclaredRoutes) ? "authored" : "none",
protectedScreens
});
if (!sorted.length) {
return null;
}
return /* @__PURE__ */ jsx(IsWithinNativeNavigator.Provider, {
value: true,
children: /* @__PURE__ */ jsx(Nav, {
...options === null || options === void 0 ? void 0 : options.props,
...props,
ref,
children: sorted
})
});
}), { Screen });
}
export { useFilterScreenChildren, useResolvedGuardedRedirects, withLayoutContext };
//# sourceMappingURL=withLayoutContext.native.js.map