UNPKG

21.5 kBJavaScriptView Raw
1/**
2 * react-router v8.4.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { useIsRSCRouterContext } from "../../context.js";
12import { useDataRouterContext, useDataRouterData, useDataRouterState, useLocation } from "../../hooks.js";
13import { warnOnce } from "../../server-runtime/warnings.js";
14import invariant from "./invariant.js";
15import { getKeyedLinksForMatches, getKeyedPrefetchLinks, getModuleLinkHrefs, getNewMatchesForLinks, isPageLinkDescriptor } from "./links.js";
16import { escapeHtml } from "./markup.js";
17import { singleFetchUrl } from "./single-fetch.js";
18import { getPartialManifest, isFogOfWarEnabled } from "./fog-of-war.js";
19import * as React$1 from "react";
20//#region lib/dom/ssr/components.tsx
21const FrameworkContext = React$1.createContext(void 0);
22FrameworkContext.displayName = "FrameworkContext";
23function useFrameworkContext() {
24 let context = React$1.useContext(FrameworkContext);
25 invariant(context, "You must render this element inside a <HydratedRouter> element");
26 return context;
27}
28function usePrefetchBehavior(prefetch, theirElementProps) {
29 let frameworkContext = React$1.useContext(FrameworkContext);
30 let [maybePrefetch, setMaybePrefetch] = React$1.useState(false);
31 let [shouldPrefetch, setShouldPrefetch] = React$1.useState(false);
32 let { onFocus, onBlur, onMouseEnter, onMouseLeave, onTouchStart } = theirElementProps;
33 let ref = React$1.useRef(null);
34 React$1.useEffect(() => {
35 if (prefetch === "render") setShouldPrefetch(true);
36 if (prefetch === "viewport") {
37 let callback = (entries) => {
38 entries.forEach((entry) => {
39 setShouldPrefetch(entry.isIntersecting);
40 });
41 };
42 let observer = new IntersectionObserver(callback, { threshold: .5 });
43 if (ref.current) observer.observe(ref.current);
44 return () => {
45 observer.disconnect();
46 };
47 }
48 }, [prefetch]);
49 React$1.useEffect(() => {
50 if (maybePrefetch) {
51 let id = setTimeout(() => {
52 setShouldPrefetch(true);
53 }, 100);
54 return () => {
55 clearTimeout(id);
56 };
57 }
58 }, [maybePrefetch]);
59 let setIntent = () => {
60 setMaybePrefetch(true);
61 };
62 let cancelIntent = () => {
63 setMaybePrefetch(false);
64 setShouldPrefetch(false);
65 };
66 if (!frameworkContext) return [
67 false,
68 ref,
69 {}
70 ];
71 if (prefetch !== "intent") return [
72 shouldPrefetch,
73 ref,
74 {}
75 ];
76 return [
77 shouldPrefetch,
78 ref,
79 {
80 onFocus: composeEventHandlers(onFocus, setIntent),
81 onBlur: composeEventHandlers(onBlur, cancelIntent),
82 onMouseEnter: composeEventHandlers(onMouseEnter, setIntent),
83 onMouseLeave: composeEventHandlers(onMouseLeave, cancelIntent),
84 onTouchStart: composeEventHandlers(onTouchStart, setIntent)
85 }
86 ];
87}
88function composeEventHandlers(theirHandler, ourHandler) {
89 return (event) => {
90 theirHandler && theirHandler(event);
91 if (!event.defaultPrevented) ourHandler(event);
92 };
93}
94function getActiveMatches(matches, errors, isSpaMode) {
95 if (isSpaMode && !isHydrated) return [matches[0]];
96 if (errors) {
97 let errorIdx = matches.findIndex((m) => errors[m.route.id] !== void 0);
98 return matches.slice(0, errorIdx + 1);
99 }
100 return matches;
101}
102const CRITICAL_CSS_DATA_ATTRIBUTE = "data-react-router-critical-css";
103/**
104* Renders all the [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
105* tags created by the route module's [`links`](../../start/framework/route-module#links)
106* export. You should render it inside the [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
107* of your document.
108*
109* @example
110* import { Links } from "react-router";
111*
112* export default function Root() {
113* return (
114* <html>
115* <head>
116* <Links />
117* </head>
118* <body></body>
119* </html>
120* );
121* }
122*
123* @public
124* @category Components
125* @mode framework
126* @param props Props
127* @param {LinksProps.nonce} props.nonce n/a
128* @param {LinksProps.crossOrigin} props.crossOrigin n/a
129* @returns A collection of React elements for [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
130* tags
131*/
132function Links({ nonce, crossOrigin }) {
133 let { isSpaMode, manifest, routeModules, criticalCss, nonce: contextNonce } = useFrameworkContext();
134 let { matches: routerMatches } = useDataRouterState("Links");
135 let { errors } = useDataRouterData("Links");
136 let matches = getActiveMatches(routerMatches, errors, isSpaMode);
137 let keyedLinks = React$1.useMemo(() => getKeyedLinksForMatches(matches, routeModules, manifest), [
138 matches,
139 routeModules,
140 manifest
141 ]);
142 if (nonce == null && contextNonce) nonce = contextNonce;
143 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, typeof criticalCss === "string" ? /* @__PURE__ */ React$1.createElement("style", {
144 [CRITICAL_CSS_DATA_ATTRIBUTE]: "",
145 nonce,
146 dangerouslySetInnerHTML: { __html: criticalCss }
147 }) : null, typeof criticalCss === "object" ? /* @__PURE__ */ React$1.createElement("link", {
148 [CRITICAL_CSS_DATA_ATTRIBUTE]: "",
149 rel: "stylesheet",
150 href: criticalCss.href,
151 nonce,
152 crossOrigin
153 }) : null, keyedLinks.map(({ key, link }) => isPageLinkDescriptor(link) ? /* @__PURE__ */ React$1.createElement(PrefetchPageLinks, {
154 key,
155 nonce,
156 ...link,
157 crossOrigin: link.crossOrigin ?? crossOrigin
158 }) : /* @__PURE__ */ React$1.createElement("link", {
159 key,
160 nonce,
161 ...link,
162 crossOrigin: link.crossOrigin ?? crossOrigin
163 })));
164}
165/**
166* Renders [`<link rel=prefetch|modulepreload>`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/rel)
167* tags for modules and data of another page to enable an instant navigation to
168* that page. [`<Link prefetch>`](./Link#prefetch) uses this internally, but you
169* can render it to prefetch a page for any other reason.
170*
171* For example, you may render one of this as the user types into a search field
172* to prefetch search results before they click through to their selection.
173*
174* @example
175* import { PrefetchPageLinks } from "react-router";
176*
177* <PrefetchPageLinks page="/absolute/path" />
178*
179* @public
180* @category Components
181* @mode framework
182* @param props Props
183* @param {PageLinkDescriptor.page} props.page n/a
184* @param props.linkProps Additional props to spread onto the [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
185* tags, such as [`crossOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/crossOrigin),
186* [`integrity`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/integrity),
187* [`rel`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/rel),
188* etc.
189* @returns A collection of React elements for [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
190* tags
191*/
192function PrefetchPageLinks({ page, ...linkProps }) {
193 let rsc = useIsRSCRouterContext();
194 let { nonce: contextNonce } = useFrameworkContext();
195 let { router } = useDataRouterContext("PrefetchPageLinks");
196 let matches = React$1.useMemo(() => router.match(page), [
197 router,
198 router.routes,
199 page
200 ]);
201 if (!matches) return null;
202 if (linkProps.nonce == null && contextNonce) linkProps = {
203 ...linkProps,
204 nonce: contextNonce
205 };
206 if (rsc) return /* @__PURE__ */ React$1.createElement(RSCPrefetchPageLinksImpl, {
207 page,
208 matches,
209 ...linkProps
210 });
211 return /* @__PURE__ */ React$1.createElement(PrefetchPageLinksImpl, {
212 page,
213 matches,
214 ...linkProps
215 });
216}
217function useKeyedPrefetchLinks(matches) {
218 let { manifest, routeModules } = useFrameworkContext();
219 let [keyedPrefetchLinks, setKeyedPrefetchLinks] = React$1.useState([]);
220 React$1.useEffect(() => {
221 let interrupted = false;
222 getKeyedPrefetchLinks(matches, manifest, routeModules).then((links) => {
223 if (!interrupted) setKeyedPrefetchLinks(links);
224 });
225 return () => {
226 interrupted = true;
227 };
228 }, [
229 matches,
230 manifest,
231 routeModules
232 ]);
233 return keyedPrefetchLinks;
234}
235function RSCPrefetchPageLinksImpl({ page, matches: nextMatches, ...linkProps }) {
236 let location = useLocation();
237 let dataHrefs = React$1.useMemo(() => {
238 if (page === location.pathname + location.search + location.hash) return [];
239 let url = singleFetchUrl(page, "rsc");
240 let hasSomeRoutesWithShouldRevalidate = false;
241 let targetRoutes = [];
242 for (let match of nextMatches) if (typeof match.route.shouldRevalidate === "function") hasSomeRoutesWithShouldRevalidate = true;
243 else targetRoutes.push(match.route.id);
244 if (hasSomeRoutesWithShouldRevalidate && targetRoutes.length > 0) url.searchParams.set("_routes", targetRoutes.join(","));
245 return [url.pathname + url.search];
246 }, [
247 page,
248 location,
249 nextMatches
250 ]);
251 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, dataHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
252 key: href,
253 rel: "prefetch",
254 as: "fetch",
255 href,
256 ...linkProps
257 })));
258}
259function PrefetchPageLinksImpl({ page, matches: nextMatches, ...linkProps }) {
260 let location = useLocation();
261 let { manifest, routeModules } = useFrameworkContext();
262 let { matches } = useDataRouterState("PrefetchPageLinks");
263 let { loaderData } = useDataRouterData("PrefetchPageLinks");
264 let newMatchesForData = React$1.useMemo(() => getNewMatchesForLinks(page, nextMatches, matches, manifest, location, "data"), [
265 page,
266 nextMatches,
267 matches,
268 manifest,
269 location
270 ]);
271 let newMatchesForAssets = React$1.useMemo(() => getNewMatchesForLinks(page, nextMatches, matches, manifest, location, "assets"), [
272 page,
273 nextMatches,
274 matches,
275 manifest,
276 location
277 ]);
278 let dataHrefs = React$1.useMemo(() => {
279 if (page === location.pathname + location.search + location.hash) return [];
280 let routesParams = /* @__PURE__ */ new Set();
281 let foundOptOutRoute = false;
282 nextMatches.forEach((m) => {
283 let manifestRoute = manifest.routes[m.route.id];
284 if (!manifestRoute || !manifestRoute.hasLoader) return;
285 if (!newMatchesForData.some((m2) => m2.route.id === m.route.id) && m.route.id in loaderData && routeModules[m.route.id]?.shouldRevalidate) foundOptOutRoute = true;
286 else if (manifestRoute.hasClientLoader) foundOptOutRoute = true;
287 else routesParams.add(m.route.id);
288 });
289 if (routesParams.size === 0) return [];
290 let url = singleFetchUrl(page, "data");
291 if (foundOptOutRoute && routesParams.size > 0) url.searchParams.set("_routes", nextMatches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(","));
292 return [url.pathname + url.search];
293 }, [
294 loaderData,
295 location,
296 manifest,
297 newMatchesForData,
298 nextMatches,
299 page,
300 routeModules
301 ]);
302 let moduleHrefs = React$1.useMemo(() => getModuleLinkHrefs(newMatchesForAssets, manifest), [newMatchesForAssets, manifest]);
303 let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
304 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, dataHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
305 key: href,
306 rel: "prefetch",
307 as: "fetch",
308 href,
309 ...linkProps
310 })), moduleHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
311 key: href,
312 rel: "modulepreload",
313 href,
314 ...linkProps
315 })), keyedPrefetchLinks.map(({ key, link }) => /* @__PURE__ */ React$1.createElement("link", {
316 key,
317 nonce: linkProps.nonce,
318 ...link,
319 crossOrigin: link.crossOrigin ?? linkProps.crossOrigin
320 })));
321}
322/**
323* Renders all the [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
324* tags created by the route module's [`meta`](../../start/framework/route-module#meta)
325* export. You should render it inside the [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
326* of your document.
327*
328* @example
329* import { Meta } from "react-router";
330*
331* export default function Root() {
332* return (
333* <html>
334* <head>
335* <Meta />
336* </head>
337* </html>
338* );
339* }
340*
341* @public
342* @category Components
343* @mode framework
344* @returns A collection of React elements for [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
345* tags
346*/
347function Meta() {
348 let { isSpaMode, routeModules } = useFrameworkContext();
349 let { matches: routerMatches } = useDataRouterState("Meta");
350 let { errors, loaderData } = useDataRouterData("Meta");
351 let location = useLocation();
352 let _matches = getActiveMatches(routerMatches, errors, isSpaMode);
353 let error = null;
354 if (errors) error = errors[_matches[_matches.length - 1].route.id];
355 let meta = [];
356 let leafMeta = null;
357 let matches = [];
358 for (let i = 0; i < _matches.length; i++) {
359 let _match = _matches[i];
360 let routeId = _match.route.id;
361 let data = loaderData[routeId];
362 let params = _match.params;
363 let routeModule = routeModules[routeId];
364 let routeMeta = [];
365 let match = {
366 id: routeId,
367 loaderData: data,
368 meta: [],
369 params: _match.params,
370 pathname: _match.pathname,
371 handle: _match.route.handle,
372 error
373 };
374 matches[i] = match;
375 if (routeModule?.meta) routeMeta = typeof routeModule.meta === "function" ? routeModule.meta({
376 loaderData: data,
377 params,
378 location,
379 matches,
380 error
381 }) : Array.isArray(routeModule.meta) ? [...routeModule.meta] : routeModule.meta;
382 else if (leafMeta) routeMeta = [...leafMeta];
383 routeMeta = routeMeta || [];
384 if (!Array.isArray(routeMeta)) throw new Error("The route at " + _match.route.path + " returns an invalid value. All route meta functions must return an array of meta objects.\n\nTo reference the meta function API, see https://reactrouter.com/start/framework/route-module#meta");
385 match.meta = routeMeta;
386 matches[i] = match;
387 meta = [...routeMeta];
388 leafMeta = meta;
389 }
390 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, meta.flat().map((metaProps) => {
391 if (!metaProps) return null;
392 if ("tagName" in metaProps) {
393 let { tagName, ...rest } = metaProps;
394 if (!isValidMetaTag(tagName)) {
395 console.warn(`A meta object uses an invalid tagName: ${tagName}. Expected either 'link' or 'meta'`);
396 return null;
397 }
398 let Comp = tagName;
399 return /* @__PURE__ */ React$1.createElement(Comp, {
400 key: JSON.stringify(rest),
401 ...rest
402 });
403 }
404 if ("title" in metaProps) return /* @__PURE__ */ React$1.createElement("title", { key: "title" }, String(metaProps.title));
405 if ("charset" in metaProps) {
406 metaProps.charSet ??= metaProps.charset;
407 delete metaProps.charset;
408 }
409 if ("charSet" in metaProps && metaProps.charSet != null) return typeof metaProps.charSet === "string" ? /* @__PURE__ */ React$1.createElement("meta", {
410 key: "charSet",
411 charSet: metaProps.charSet
412 }) : null;
413 if ("script:ld+json" in metaProps) try {
414 let json = JSON.stringify(metaProps["script:ld+json"]);
415 return /* @__PURE__ */ React$1.createElement("script", {
416 key: `script:ld+json:${json}`,
417 type: "application/ld+json",
418 dangerouslySetInnerHTML: { __html: escapeHtml(json) }
419 });
420 } catch {
421 return null;
422 }
423 return /* @__PURE__ */ React$1.createElement("meta", {
424 key: JSON.stringify(metaProps),
425 ...metaProps
426 });
427 }));
428}
429function isValidMetaTag(tagName) {
430 return typeof tagName === "string" && /^(meta|link)$/.test(tagName);
431}
432/**
433* Tracks whether hydration is finished, so scripts can be skipped
434* during client-side updates.
435*/
436let isHydrated = false;
437function setIsHydrated() {
438 isHydrated = true;
439}
440/**
441* Renders the client runtime of your app. It should be rendered inside the
442* [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)
443* of the document.
444*
445* If server rendering, you can omit `<Scripts/>` and the app will work as a
446* traditional web app without JavaScript, relying solely on HTML and browser
447* behaviors.
448*
449* @example
450* import { Scripts } from "react-router";
451*
452* export default function Root() {
453* return (
454* <html>
455* <head />
456* <body>
457* <Scripts />
458* </body>
459* </html>
460* );
461* }
462*
463* @public
464* @category Components
465* @mode framework
466* @param scriptProps Additional props to spread onto the [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
467* tags, such as [`crossOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/crossOrigin),
468* [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce),
469* etc.
470* @returns A collection of React elements for [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
471* tags
472*/
473function Scripts(scriptProps) {
474 let { manifest, serverHandoffString, isSpaMode, renderMeta, routeDiscovery, ssr, nonce: contextNonce } = useFrameworkContext();
475 let { router, static: isStatic, staticContext } = useDataRouterContext("Scripts");
476 let { matches: routerMatches } = useDataRouterState("Scripts");
477 let isRSCRouterContext = useIsRSCRouterContext();
478 let enableFogOfWar = isFogOfWarEnabled(routeDiscovery, ssr);
479 if (scriptProps.nonce == null && contextNonce) scriptProps = {
480 ...scriptProps,
481 nonce: contextNonce
482 };
483 if (renderMeta) renderMeta.didRenderScripts = true;
484 let matches = getActiveMatches(routerMatches, null, isSpaMode);
485 React$1.useEffect(() => {
486 setIsHydrated();
487 }, []);
488 let initialScripts = React$1.useMemo(() => {
489 if (isRSCRouterContext) return null;
490 let contextScript = staticContext ? `window.__reactRouterContext = ${serverHandoffString};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());` : " ";
491 let routeModulesScript = !isStatic ? " " : `${manifest.hmr?.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${!enableFogOfWar ? `import ${JSON.stringify(manifest.url)}` : ""};
492${matches.map((match, routeIndex) => {
493 let routeVarName = `route${routeIndex}`;
494 let manifestEntry = manifest.routes[match.route.id];
495 invariant(manifestEntry, `Route ${match.route.id} not found in manifest`);
496 let { clientActionModule, clientLoaderModule, clientMiddlewareModule, hydrateFallbackModule, module } = manifestEntry;
497 let chunks = [
498 ...clientActionModule ? [{
499 module: clientActionModule,
500 varName: `${routeVarName}_clientAction`
501 }] : [],
502 ...clientLoaderModule ? [{
503 module: clientLoaderModule,
504 varName: `${routeVarName}_clientLoader`
505 }] : [],
506 ...clientMiddlewareModule ? [{
507 module: clientMiddlewareModule,
508 varName: `${routeVarName}_clientMiddleware`
509 }] : [],
510 ...hydrateFallbackModule ? [{
511 module: hydrateFallbackModule,
512 varName: `${routeVarName}_HydrateFallback`
513 }] : [],
514 {
515 module,
516 varName: `${routeVarName}_main`
517 }
518 ];
519 if (chunks.length === 1) return `import * as ${routeVarName} from ${JSON.stringify(module)};`;
520 return [chunks.map((chunk) => `import * as ${chunk.varName} from "${chunk.module}";`).join("\n"), `const ${routeVarName} = {${chunks.map((chunk) => `...${chunk.varName}`).join(",")}};`].join("\n");
521 }).join("\n")}
522 ${enableFogOfWar ? `window.__reactRouterManifest = ${JSON.stringify(getPartialManifest(manifest, router), null, 2)};` : ""}
523 window.__reactRouterRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};
524
525import(${JSON.stringify(manifest.entry.module)});`;
526 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement("script", {
527 ...scriptProps,
528 suppressHydrationWarning: true,
529 dangerouslySetInnerHTML: { __html: contextScript },
530 type: void 0
531 }), /* @__PURE__ */ React$1.createElement("script", {
532 ...scriptProps,
533 suppressHydrationWarning: true,
534 dangerouslySetInnerHTML: { __html: routeModulesScript },
535 type: "module",
536 async: true
537 }));
538 }, []);
539 let preloads = isHydrated || isRSCRouterContext ? [] : [...new Set(manifest.entry.imports.concat(getModuleLinkHrefs(matches, manifest, { includeHydrateFallback: true })))];
540 let sri = typeof manifest.sri === "object" ? manifest.sri : {};
541 warnOnce(!isRSCRouterContext, "The <Scripts /> element is a no-op when using RSC and can be safely removed.");
542 return isHydrated || isRSCRouterContext ? null : /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, typeof manifest.sri === "object" ? /* @__PURE__ */ React$1.createElement("script", {
543 ...scriptProps,
544 "rr-importmap": "",
545 type: "importmap",
546 suppressHydrationWarning: true,
547 dangerouslySetInnerHTML: { __html: JSON.stringify({ integrity: sri }) }
548 }) : null, !enableFogOfWar ? /* @__PURE__ */ React$1.createElement("link", {
549 rel: "modulepreload",
550 href: manifest.url,
551 crossOrigin: scriptProps.crossOrigin,
552 integrity: sri[manifest.url],
553 nonce: scriptProps.nonce,
554 suppressHydrationWarning: true
555 }) : null, /* @__PURE__ */ React$1.createElement("link", {
556 rel: "modulepreload",
557 href: manifest.entry.module,
558 crossOrigin: scriptProps.crossOrigin,
559 integrity: sri[manifest.entry.module],
560 nonce: scriptProps.nonce,
561 suppressHydrationWarning: true
562 }), preloads.map((path) => /* @__PURE__ */ React$1.createElement("link", {
563 key: path,
564 rel: "modulepreload",
565 href: path,
566 crossOrigin: scriptProps.crossOrigin,
567 integrity: sri[path],
568 nonce: scriptProps.nonce,
569 suppressHydrationWarning: true
570 })), initialScripts);
571}
572function mergeRefs(...refs) {
573 return (value) => {
574 refs.forEach((ref) => {
575 if (typeof ref === "function") ref(value);
576 else if (ref != null) ref.current = value;
577 });
578 };
579}
580//#endregion
581export { CRITICAL_CSS_DATA_ATTRIBUTE, FrameworkContext, Links, Meta, PrefetchPageLinks, Scripts, mergeRefs, setIsHydrated, useFrameworkContext, usePrefetchBehavior };