@tanstack/react-router 1.34.0 → 1.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"Transitioner.js","sources":["../../src/Transitioner.tsx"],"sourcesContent":["import * as React from 'react'\nimport { pick, useLayoutEffect, usePrevious } from './utils'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\n\nexport function Transitioner() {\n const router = useRouter()\n const mountLoadForRouter = React.useRef({ router, mounted: false })\n const routerState = useRouterState({\n select: (s) =>\n pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),\n })\n\n const [isTransitioning, startReactTransition_] = React.useTransition()\n // Track pending state changes\n const hasPendingMatches = useRouterState({\n select: (s) => s.matches.some((d) => d.status === 'pending'),\n })\n\n const previousIsLoading = usePrevious(routerState.isLoading)\n\n const isAnyPending =\n routerState.isLoading || isTransitioning || hasPendingMatches\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n router.startReactTransition = startReactTransition_\n\n // Subscribe to location changes\n // and try to load the new location\n useLayoutEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n })\n\n if (router.state.location.href !== nextLocation.href) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n }, [router, router.history])\n\n // Try to load the initial location\n useLayoutEffect(() => {\n if (\n window.__TSR_DEHYDRATED__ ||\n (mountLoadForRouter.current.router === router &&\n mountLoadForRouter.current.mounted)\n ) {\n return\n }\n mountLoadForRouter.current = { router, mounted: true }\n\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n\n tryLoad()\n }, [router])\n\n useLayoutEffect(() => {\n // The router was loading and now it's not\n if (previousIsLoading && !routerState.isLoading) {\n const toLocation = router.state.location\n const fromLocation = router.state.resolvedLocation\n const pathChanged = fromLocation.href !== toLocation.href\n\n router.emit({\n type: 'onLoad',\n fromLocation,\n toLocation,\n pathChanged,\n })\n\n // if (router.viewTransitionPromise) {\n // console.log('resolving view transition promise')\n // }\n // router.viewTransitionPromise?.resolve(true)\n }\n }, [previousIsLoading, router, routerState.isLoading])\n\n useLayoutEffect(() => {\n // The router was pending and now it's not\n if (previousIsAnyPending && !isAnyPending) {\n const toLocation = router.state.location\n const fromLocation = router.state.resolvedLocation\n const pathChanged = fromLocation.href !== toLocation.href\n\n router.emit({\n type: 'onResolved',\n fromLocation,\n toLocation,\n pathChanged,\n })\n\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n\n if ((document as any).querySelector) {\n if (router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView()\n }\n }\n }\n }\n }, [isAnyPending, previousIsAnyPending, router])\n\n return null\n}\n"],"names":[],"mappings":";;;;AAKO,SAAS,eAAe;AAC7B,QAAM,SAAS;AACf,QAAM,qBAAqB,MAAM,OAAO,EAAE,QAAQ,SAAS,OAAO;AAClE,QAAM,cAAc,eAAe;AAAA,IACjC,QAAQ,CAAC,MACP,KAAK,GAAG,CAAC,aAAa,YAAY,oBAAoB,iBAAiB,CAAC;AAAA,EAAA,CAC3E;AAED,QAAM,CAAC,iBAAiB,qBAAqB,IAAI,MAAM,cAAc;AAErE,QAAM,oBAAoB,eAAe;AAAA,IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS;AAAA,EAAA,CAC5D;AAEK,QAAA,oBAAoB,YAAY,YAAY,SAAS;AAErD,QAAA,eACJ,YAAY,aAAa,mBAAmB;AACxC,QAAA,uBAAuB,YAAY,YAAY;AAErD,SAAO,uBAAuB;AAI9B,kBAAgB,MAAM;AACpB,UAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;AAE5C,UAAA,eAAe,OAAO,cAAc;AAAA,MACxC,IAAI,OAAO,eAAe;AAAA,MAC1B,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IAAA,CACR;AAED,QAAI,OAAO,MAAM,SAAS,SAAS,aAAa,MAAM;AACpD,aAAO,eAAe,EAAE,GAAG,cAAc,SAAS,MAAM;AAAA,IAC1D;AAEA,WAAO,MAAM;AACL;IAAA;AAAA,EAEP,GAAA,CAAC,QAAQ,OAAO,OAAO,CAAC;AAG3B,kBAAgB,MAAM;AAElB,QAAA,OAAO,sBACN,mBAAmB,QAAQ,WAAW,UACrC,mBAAmB,QAAQ,SAC7B;AACA;AAAA,IACF;AACA,uBAAmB,UAAU,EAAE,QAAQ,SAAS,KAAK;AAErD,UAAM,UAAU,YAAY;AACtB,UAAA;AACF,cAAM,OAAO;eACN,KAAK;AACZ,gBAAQ,MAAM,GAAG;AAAA,MACnB;AAAA,IAAA;AAGM;EAAA,GACP,CAAC,MAAM,CAAC;AAEX,kBAAgB,MAAM;AAEhB,QAAA,qBAAqB,CAAC,YAAY,WAAW;AACzC,YAAA,aAAa,OAAO,MAAM;AAC1B,YAAA,eAAe,OAAO,MAAM;AAC5B,YAAA,cAAc,aAAa,SAAS,WAAW;AAErD,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IAMH;AAAA,KACC,CAAC,mBAAmB,QAAQ,YAAY,SAAS,CAAC;AAErD,kBAAgB,MAAM;AAEhB,QAAA,wBAAwB,CAAC,cAAc;AACnC,YAAA,aAAa,OAAO,MAAM;AAC1B,YAAA,eAAe,OAAO,MAAM;AAC5B,YAAA,cAAc,aAAa,SAAS,WAAW;AAErD,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AAEM,aAAA,QAAQ,SAAS,CAAC,OAAO;AAAA,QAC9B,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,kBAAkB,EAAE;AAAA,MACpB,EAAA;AAEF,UAAK,SAAiB,eAAe;AACnC,YAAI,OAAO,MAAM,SAAS,SAAS,IAAI;AACrC,gBAAM,KAAK,SAAS,eAAe,OAAO,MAAM,SAAS,IAAI;AAC7D,cAAI,IAAI;AACN,eAAG,eAAe;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACC,GAAA,CAAC,cAAc,sBAAsB,MAAM,CAAC;AAExC,SAAA;AACT;"}
1
+ {"version":3,"file":"Transitioner.js","sources":["../../src/Transitioner.tsx"],"sourcesContent":["import * as React from 'react'\nimport { pick, useLayoutEffect, usePrevious } from './utils'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\n\nexport function Transitioner() {\n const router = useRouter()\n const mountLoadForRouter = React.useRef({ router, mounted: false })\n const routerState = useRouterState({\n select: (s) =>\n pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),\n })\n\n const [isTransitioning, startReactTransition_] = React.useTransition()\n // Track pending state changes\n const hasPendingMatches = useRouterState({\n select: (s) => s.matches.some((d) => d.status === 'pending'),\n })\n\n const previousIsLoading = usePrevious(routerState.isLoading)\n\n const isAnyPending =\n routerState.isLoading || isTransitioning || hasPendingMatches\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n if (!router.isServer) {\n router.startReactTransition = startReactTransition_\n }\n\n // Subscribe to location changes\n // and try to load the new location\n useLayoutEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n })\n\n if (router.state.location.href !== nextLocation.href) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n }, [router, router.history])\n\n // Try to load the initial location\n useLayoutEffect(() => {\n if (\n window.__TSR_DEHYDRATED__ ||\n (mountLoadForRouter.current.router === router &&\n mountLoadForRouter.current.mounted)\n ) {\n return\n }\n mountLoadForRouter.current = { router, mounted: true }\n\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n\n tryLoad()\n }, [router])\n\n useLayoutEffect(() => {\n // The router was loading and now it's not\n if (previousIsLoading && !routerState.isLoading) {\n const toLocation = router.state.location\n const fromLocation = router.state.resolvedLocation\n const pathChanged = fromLocation.href !== toLocation.href\n\n router.emit({\n type: 'onLoad',\n fromLocation,\n toLocation,\n pathChanged,\n })\n\n // if (router.viewTransitionPromise) {\n // console.log('resolving view transition promise')\n // }\n // router.viewTransitionPromise?.resolve(true)\n }\n }, [previousIsLoading, router, routerState.isLoading])\n\n useLayoutEffect(() => {\n // The router was pending and now it's not\n if (previousIsAnyPending && !isAnyPending) {\n const toLocation = router.state.location\n const fromLocation = router.state.resolvedLocation\n const pathChanged = fromLocation.href !== toLocation.href\n\n router.emit({\n type: 'onResolved',\n fromLocation,\n toLocation,\n pathChanged,\n })\n\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n\n if ((document as any).querySelector) {\n if (router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView()\n }\n }\n }\n }\n }, [isAnyPending, previousIsAnyPending, router])\n\n return null\n}\n"],"names":[],"mappings":";;;;AAKO,SAAS,eAAe;AAC7B,QAAM,SAAS;AACf,QAAM,qBAAqB,MAAM,OAAO,EAAE,QAAQ,SAAS,OAAO;AAClE,QAAM,cAAc,eAAe;AAAA,IACjC,QAAQ,CAAC,MACP,KAAK,GAAG,CAAC,aAAa,YAAY,oBAAoB,iBAAiB,CAAC;AAAA,EAAA,CAC3E;AAED,QAAM,CAAC,iBAAiB,qBAAqB,IAAI,MAAM,cAAc;AAErE,QAAM,oBAAoB,eAAe;AAAA,IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS;AAAA,EAAA,CAC5D;AAEK,QAAA,oBAAoB,YAAY,YAAY,SAAS;AAErD,QAAA,eACJ,YAAY,aAAa,mBAAmB;AACxC,QAAA,uBAAuB,YAAY,YAAY;AAEjD,MAAA,CAAC,OAAO,UAAU;AACpB,WAAO,uBAAuB;AAAA,EAChC;AAIA,kBAAgB,MAAM;AACpB,UAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;AAE5C,UAAA,eAAe,OAAO,cAAc;AAAA,MACxC,IAAI,OAAO,eAAe;AAAA,MAC1B,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IAAA,CACR;AAED,QAAI,OAAO,MAAM,SAAS,SAAS,aAAa,MAAM;AACpD,aAAO,eAAe,EAAE,GAAG,cAAc,SAAS,MAAM;AAAA,IAC1D;AAEA,WAAO,MAAM;AACL;IAAA;AAAA,EAEP,GAAA,CAAC,QAAQ,OAAO,OAAO,CAAC;AAG3B,kBAAgB,MAAM;AAElB,QAAA,OAAO,sBACN,mBAAmB,QAAQ,WAAW,UACrC,mBAAmB,QAAQ,SAC7B;AACA;AAAA,IACF;AACA,uBAAmB,UAAU,EAAE,QAAQ,SAAS,KAAK;AAErD,UAAM,UAAU,YAAY;AACtB,UAAA;AACF,cAAM,OAAO;eACN,KAAK;AACZ,gBAAQ,MAAM,GAAG;AAAA,MACnB;AAAA,IAAA;AAGM;EAAA,GACP,CAAC,MAAM,CAAC;AAEX,kBAAgB,MAAM;AAEhB,QAAA,qBAAqB,CAAC,YAAY,WAAW;AACzC,YAAA,aAAa,OAAO,MAAM;AAC1B,YAAA,eAAe,OAAO,MAAM;AAC5B,YAAA,cAAc,aAAa,SAAS,WAAW;AAErD,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IAMH;AAAA,KACC,CAAC,mBAAmB,QAAQ,YAAY,SAAS,CAAC;AAErD,kBAAgB,MAAM;AAEhB,QAAA,wBAAwB,CAAC,cAAc;AACnC,YAAA,aAAa,OAAO,MAAM;AAC1B,YAAA,eAAe,OAAO,MAAM;AAC5B,YAAA,cAAc,aAAa,SAAS,WAAW;AAErD,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AAEM,aAAA,QAAQ,SAAS,CAAC,OAAO;AAAA,QAC9B,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,kBAAkB,EAAE;AAAA,MACpB,EAAA;AAEF,UAAK,SAAiB,eAAe;AACnC,YAAI,OAAO,MAAM,SAAS,SAAS,IAAI;AACrC,gBAAM,KAAK,SAAS,eAAe,OAAO,MAAM,SAAS,IAAI;AAC7D,cAAI,IAAI;AACN,eAAG,eAAe;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACC,GAAA,CAAC,cAAc,sBAAsB,MAAM,CAAC;AAExC,SAAA;AACT;"}
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  export type AwaitOptions<T> = {
4
4
  promise: DeferredPromise<T>;
5
5
  };
6
- export declare function useAwaited<T>({ promise }: AwaitOptions<T>): [T];
6
+ export declare function useAwaited<T>({ promise, }: AwaitOptions<T>): [T, DeferredPromise<T>];
7
7
  export declare function Await<T>(props: AwaitOptions<T> & {
8
8
  fallback?: React.ReactNode;
9
9
  children: (result: T) => React.ReactNode;
@@ -1,11 +1,13 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import warning from "tiny-warning";
4
4
  import { useRouter } from "./useRouter.js";
5
5
  import { defaultSerializeError } from "./router.js";
6
6
  import { isDehydratedDeferred } from "./defer.js";
7
7
  import { isServerSideError, defaultDeserializeError } from "./Matches.js";
8
- function useAwaited({ promise }) {
8
+ function useAwaited({
9
+ promise
10
+ }) {
9
11
  var _a, _b;
10
12
  const router = useRouter();
11
13
  const state = promise.__deferredState;
@@ -36,17 +38,6 @@ function useAwaited({ promise }) {
36
38
  if (state.status === "pending") {
37
39
  throw isDehydratedDeferred(promise) ? state.promise : promise;
38
40
  }
39
- if (!isDehydratedDeferred(promise)) {
40
- router.injectHtml(
41
- `<script class='tsr_deferred_data'>window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}
42
- if (window.__TSR__ROUTER__) {
43
- let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}');
44
- if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid});
45
- }
46
- document.querySelectorAll('.tsr_deferred_data').forEach((el) => el.parentElement.removeChild(el));
47
- <\/script>`
48
- );
49
- }
50
41
  if (state.status === "error") {
51
42
  if (typeof document !== "undefined") {
52
43
  if (isServerSideError(state.error)) {
@@ -65,7 +56,7 @@ function useAwaited({ promise }) {
65
56
  };
66
57
  }
67
58
  }
68
- return [promise.__deferredState.data];
59
+ return [promise.__deferredState.data, promise];
69
60
  }
70
61
  function Await(props) {
71
62
  const inner = /* @__PURE__ */ jsx(AwaitInner, { ...props });
@@ -75,8 +66,39 @@ function Await(props) {
75
66
  return inner;
76
67
  }
77
68
  function AwaitInner(props) {
78
- const awaited = useAwaited(props);
79
- return props.children(...awaited);
69
+ const router = useRouter();
70
+ const [data, promise] = useAwaited(props);
71
+ const state = promise.__deferredState;
72
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
73
+ !isDehydratedDeferred(promise) ? /* @__PURE__ */ jsx(
74
+ ScriptOnce,
75
+ {
76
+ children: `window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}
77
+ if (window.__TSR__ROUTER__) {
78
+ let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}');
79
+ if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid});
80
+ }
81
+ document.querySelectorAll('.tsr-script-once').forEach((el) => el.parentElement.removeChild(el));`
82
+ }
83
+ ) : null,
84
+ props.children(data)
85
+ ] });
86
+ }
87
+ function ScriptOnce({
88
+ className,
89
+ children,
90
+ ...rest
91
+ }) {
92
+ return /* @__PURE__ */ jsx(
93
+ "script",
94
+ {
95
+ ...rest,
96
+ className: `tsr-script-once ${className || ""}`,
97
+ dangerouslySetInnerHTML: {
98
+ __html: children
99
+ }
100
+ }
101
+ );
80
102
  }
81
103
  export {
82
104
  Await,
@@ -1 +1 @@
1
- {"version":3,"file":"awaited.js","sources":["../../src/awaited.tsx"],"sourcesContent":["import * as React from 'react'\nimport warning from 'tiny-warning'\nimport { useRouter } from './useRouter'\nimport { defaultSerializeError } from './router'\nimport { isDehydratedDeferred } from './defer'\nimport { defaultDeserializeError, isServerSideError } from './Matches'\nimport type { DeferredPromise } from './defer'\n\nexport type AwaitOptions<T> = {\n promise: DeferredPromise<T>\n}\n\nexport function useAwaited<T>({ promise }: AwaitOptions<T>): [T] {\n const router = useRouter()\n // const rerender = React.useReducer((x) => x + 1, 0)[1]\n\n const state = promise.__deferredState\n\n // Dehydrated promises only\n // Successful or errored deferred promises mean they\n // were resolved on the server and no further action is needed\n if (isDehydratedDeferred(promise) && state.status === 'pending') {\n const streamedData = (window as any)[`__TSR__DEFERRED__${state.uid}`]\n\n if (streamedData) {\n Object.assign(state, router.options.transformer.parse(streamedData))\n } else {\n let token = router.registeredDeferredsIds.get(state.uid)\n\n // If we haven't yet, create a promise and resolver that our streamed HTML can use\n // when the client-side data is streamed in and ready.\n if (!token) {\n token = {}\n router.registeredDeferredsIds.set(state.uid, token)\n router.registeredDeferreds.set(token, state)\n\n Object.assign(state, {\n resolve: () => {\n state.__resolvePromise?.()\n // rerender()\n },\n promise: new Promise((r) => {\n state.__resolvePromise = r as any\n }),\n __resolvePromise: () => {},\n })\n }\n }\n }\n\n // If the promise is pending, always throw the state.promise\n // For originating promises, this will be the original promise\n // For dehydrated promises, this will be the placeholder promise\n // that will be resolved when the server sends the real data\n if (state.status === 'pending') {\n throw isDehydratedDeferred(promise) ? state.promise : promise\n }\n\n // If we are the originator of the promise,\n // inject the state into the HTML stream\n if (!isDehydratedDeferred(promise)) {\n router.injectHtml(\n `<script class='tsr_deferred_data'>window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}\n if (window.__TSR__ROUTER__) {\n let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}');\n if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid});\n }\n document.querySelectorAll('.tsr_deferred_data').forEach((el) => el.parentElement.removeChild(el));\n</script>`,\n )\n }\n\n if (state.status === 'error') {\n if (typeof document !== 'undefined') {\n if (isServerSideError(state.error)) {\n throw (\n router.options.errorSerializer?.deserialize ?? defaultDeserializeError\n )(state.error.data as any)\n } else {\n warning(\n false,\n \"Encountered a server-side error that doesn't fit the expected shape\",\n )\n throw state.error\n }\n } else {\n throw {\n data: (\n router.options.errorSerializer?.serialize ?? defaultSerializeError\n )(state.error),\n __isServerError: true,\n }\n }\n }\n\n return [promise.__deferredState.data as any]\n}\n\nexport function Await<T>(\n props: AwaitOptions<T> & {\n fallback?: React.ReactNode\n children: (result: T) => React.ReactNode\n },\n) {\n const inner = <AwaitInner {...props} />\n if (props.fallback) {\n return <React.Suspense fallback={props.fallback}>{inner}</React.Suspense>\n }\n return inner\n}\n\nfunction AwaitInner<T>(\n props: AwaitOptions<T> & {\n fallback?: React.ReactNode\n children: (result: T) => React.ReactNode\n },\n) {\n const awaited = useAwaited(props)\n return props.children(...awaited) as React.JSX.Element\n}\n"],"names":["_a"],"mappings":";;;;;;;AAYgB,SAAA,WAAc,EAAE,WAAiC;;AAC/D,QAAM,SAAS;AAGf,QAAM,QAAQ,QAAQ;AAKtB,MAAI,qBAAqB,OAAO,KAAK,MAAM,WAAW,WAAW;AAC/D,UAAM,eAAgB,OAAe,oBAAoB,MAAM,GAAG,EAAE;AAEpE,QAAI,cAAc;AAChB,aAAO,OAAO,OAAO,OAAO,QAAQ,YAAY,MAAM,YAAY,CAAC;AAAA,IAAA,OAC9D;AACL,UAAI,QAAQ,OAAO,uBAAuB,IAAI,MAAM,GAAG;AAIvD,UAAI,CAAC,OAAO;AACV,gBAAQ,CAAA;AACR,eAAO,uBAAuB,IAAI,MAAM,KAAK,KAAK;AAC3C,eAAA,oBAAoB,IAAI,OAAO,KAAK;AAE3C,eAAO,OAAO,OAAO;AAAA,UACnB,SAAS,MAAM;;AACb,aAAAA,MAAA,MAAM,qBAAN,gBAAAA,IAAA;AAAA,UAEF;AAAA,UACA,SAAS,IAAI,QAAQ,CAAC,MAAM;AAC1B,kBAAM,mBAAmB;AAAA,UAAA,CAC1B;AAAA,UACD,kBAAkB,MAAM;AAAA,UAAC;AAAA,QAAA,CAC1B;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAMI,MAAA,MAAM,WAAW,WAAW;AAC9B,UAAM,qBAAqB,OAAO,IAAI,MAAM,UAAU;AAAA,EACxD;AAII,MAAA,CAAC,qBAAqB,OAAO,GAAG;AAC3B,WAAA;AAAA,MACL,6DAA6D,MAAM,GAAG,MAAM,KAAK,UAAU,OAAO,QAAQ,YAAY,UAAU,KAAK,CAAC,CAAC;AAAA;AAAA,yDAEpF,MAAM,GAAG;AAAA,6DACL,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,EAKpE;AAEI,MAAA,MAAM,WAAW,SAAS;AACxB,QAAA,OAAO,aAAa,aAAa;AAC/B,UAAA,kBAAkB,MAAM,KAAK,GAAG;AAClC,iBACE,YAAO,QAAQ,oBAAf,mBAAgC,gBAAe,yBAC/C,MAAM,MAAM,IAAW;AAAA,MAAA,OACpB;AACL;AAAA,UACE;AAAA,UACA;AAAA,QAAA;AAEF,cAAM,MAAM;AAAA,MACd;AAAA,IAAA,OACK;AACC,YAAA;AAAA,QACJ,SACE,YAAO,QAAQ,oBAAf,mBAAgC,cAAa,uBAC7C,MAAM,KAAK;AAAA,QACb,iBAAiB;AAAA,MAAA;AAAA,IAErB;AAAA,EACF;AAEO,SAAA,CAAC,QAAQ,gBAAgB,IAAW;AAC7C;AAEO,SAAS,MACd,OAIA;AACA,QAAM,QAAQ,oBAAC,YAAY,EAAA,GAAG,MAAO,CAAA;AACrC,MAAI,MAAM,UAAU;AAClB,+BAAQ,MAAM,UAAN,EAAe,UAAU,MAAM,UAAW,UAAM,MAAA,CAAA;AAAA,EAC1D;AACO,SAAA;AACT;AAEA,SAAS,WACP,OAIA;AACM,QAAA,UAAU,WAAW,KAAK;AACzB,SAAA,MAAM,SAAS,GAAG,OAAO;AAClC;"}
1
+ {"version":3,"file":"awaited.js","sources":["../../src/awaited.tsx"],"sourcesContent":["import * as React from 'react'\nimport warning from 'tiny-warning'\nimport { useRouter } from './useRouter'\nimport { defaultSerializeError } from './router'\nimport { isDehydratedDeferred } from './defer'\nimport { defaultDeserializeError, isServerSideError } from './Matches'\nimport type { DeferredPromise } from './defer'\n\nexport type AwaitOptions<T> = {\n promise: DeferredPromise<T>\n}\n\nexport function useAwaited<T>({\n promise,\n}: AwaitOptions<T>): [T, DeferredPromise<T>] {\n const router = useRouter()\n // const rerender = React.useReducer((x) => x + 1, 0)[1]\n\n const state = promise.__deferredState\n\n // Dehydrated promises only\n // Successful or errored deferred promises mean they\n // were resolved on the server and no further action is needed\n if (isDehydratedDeferred(promise) && state.status === 'pending') {\n const streamedData = (window as any)[`__TSR__DEFERRED__${state.uid}`]\n\n if (streamedData) {\n Object.assign(state, router.options.transformer.parse(streamedData))\n } else {\n let token = router.registeredDeferredsIds.get(state.uid)\n\n // If we haven't yet, create a promise and resolver that our streamed HTML can use\n // when the client-side data is streamed in and ready.\n if (!token) {\n token = {}\n router.registeredDeferredsIds.set(state.uid, token)\n router.registeredDeferreds.set(token, state)\n\n Object.assign(state, {\n resolve: () => {\n state.__resolvePromise?.()\n // rerender()\n },\n promise: new Promise((r) => {\n state.__resolvePromise = r as any\n }),\n __resolvePromise: () => {},\n })\n }\n }\n }\n\n // If the promise is pending, always throw the state.promise\n // For originating promises, this will be the original promise\n // For dehydrated promises, this will be the placeholder promise\n // that will be resolved when the server sends the real data\n if (state.status === 'pending') {\n throw isDehydratedDeferred(promise) ? state.promise : promise\n }\n\n if (state.status === 'error') {\n if (typeof document !== 'undefined') {\n if (isServerSideError(state.error)) {\n throw (\n router.options.errorSerializer?.deserialize ?? defaultDeserializeError\n )(state.error.data as any)\n } else {\n warning(\n false,\n \"Encountered a server-side error that doesn't fit the expected shape\",\n )\n throw state.error\n }\n } else {\n throw {\n data: (\n router.options.errorSerializer?.serialize ?? defaultSerializeError\n )(state.error),\n __isServerError: true,\n }\n }\n }\n\n return [promise.__deferredState.data as any, promise]\n}\n\nexport function Await<T>(\n props: AwaitOptions<T> & {\n fallback?: React.ReactNode\n children: (result: T) => React.ReactNode\n },\n) {\n const inner = <AwaitInner {...props} />\n if (props.fallback) {\n return <React.Suspense fallback={props.fallback}>{inner}</React.Suspense>\n }\n return inner\n}\n\nfunction AwaitInner<T>(\n props: AwaitOptions<T> & {\n fallback?: React.ReactNode\n children: (result: T) => React.ReactNode\n },\n) {\n const router = useRouter()\n const [data, promise] = useAwaited(props)\n const state = promise.__deferredState\n // If we are the originator of the promise,\n // inject the state into the HTML stream\n return (\n <>\n {!isDehydratedDeferred(promise) ? (\n <ScriptOnce\n children={`window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}\n if (window.__TSR__ROUTER__) {\n let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}');\n if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid});\n }\n document.querySelectorAll('.tsr-script-once').forEach((el) => el.parentElement.removeChild(el));`}\n />\n ) : null}\n {props.children(data)}\n </>\n )\n}\n\nfunction ScriptOnce({\n className,\n children,\n ...rest\n}: { children: string } & React.HTMLProps<HTMLScriptElement>) {\n return (\n <script\n {...rest}\n className={`tsr-script-once ${className || ''}`}\n dangerouslySetInnerHTML={{\n __html: children,\n }}\n />\n )\n}\n"],"names":["_a"],"mappings":";;;;;;;AAYO,SAAS,WAAc;AAAA,EAC5B;AACF,GAA6C;;AAC3C,QAAM,SAAS;AAGf,QAAM,QAAQ,QAAQ;AAKtB,MAAI,qBAAqB,OAAO,KAAK,MAAM,WAAW,WAAW;AAC/D,UAAM,eAAgB,OAAe,oBAAoB,MAAM,GAAG,EAAE;AAEpE,QAAI,cAAc;AAChB,aAAO,OAAO,OAAO,OAAO,QAAQ,YAAY,MAAM,YAAY,CAAC;AAAA,IAAA,OAC9D;AACL,UAAI,QAAQ,OAAO,uBAAuB,IAAI,MAAM,GAAG;AAIvD,UAAI,CAAC,OAAO;AACV,gBAAQ,CAAA;AACR,eAAO,uBAAuB,IAAI,MAAM,KAAK,KAAK;AAC3C,eAAA,oBAAoB,IAAI,OAAO,KAAK;AAE3C,eAAO,OAAO,OAAO;AAAA,UACnB,SAAS,MAAM;;AACb,aAAAA,MAAA,MAAM,qBAAN,gBAAAA,IAAA;AAAA,UAEF;AAAA,UACA,SAAS,IAAI,QAAQ,CAAC,MAAM;AAC1B,kBAAM,mBAAmB;AAAA,UAAA,CAC1B;AAAA,UACD,kBAAkB,MAAM;AAAA,UAAC;AAAA,QAAA,CAC1B;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAMI,MAAA,MAAM,WAAW,WAAW;AAC9B,UAAM,qBAAqB,OAAO,IAAI,MAAM,UAAU;AAAA,EACxD;AAEI,MAAA,MAAM,WAAW,SAAS;AACxB,QAAA,OAAO,aAAa,aAAa;AAC/B,UAAA,kBAAkB,MAAM,KAAK,GAAG;AAClC,iBACE,YAAO,QAAQ,oBAAf,mBAAgC,gBAAe,yBAC/C,MAAM,MAAM,IAAW;AAAA,MAAA,OACpB;AACL;AAAA,UACE;AAAA,UACA;AAAA,QAAA;AAEF,cAAM,MAAM;AAAA,MACd;AAAA,IAAA,OACK;AACC,YAAA;AAAA,QACJ,SACE,YAAO,QAAQ,oBAAf,mBAAgC,cAAa,uBAC7C,MAAM,KAAK;AAAA,QACb,iBAAiB;AAAA,MAAA;AAAA,IAErB;AAAA,EACF;AAEA,SAAO,CAAC,QAAQ,gBAAgB,MAAa,OAAO;AACtD;AAEO,SAAS,MACd,OAIA;AACA,QAAM,QAAQ,oBAAC,YAAY,EAAA,GAAG,MAAO,CAAA;AACrC,MAAI,MAAM,UAAU;AAClB,+BAAQ,MAAM,UAAN,EAAe,UAAU,MAAM,UAAW,UAAM,MAAA,CAAA;AAAA,EAC1D;AACO,SAAA;AACT;AAEA,SAAS,WACP,OAIA;AACA,QAAM,SAAS;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,WAAW,KAAK;AACxC,QAAM,QAAQ,QAAQ;AAGtB,SAEK,qBAAA,UAAA,EAAA,UAAA;AAAA,IAAC,CAAA,qBAAqB,OAAO,IAC5B;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,UAAU,2BAA2B,MAAM,GAAG,MAAM,KAAK,UAAU,OAAO,QAAQ,YAAY,UAAU,KAAK,CAAC,CAAC;AAAA;AAAA,yDAEhE,MAAM,GAAG;AAAA,6DACL,MAAM,GAAG;AAAA;AAAA;AAAA,MAAA;AAAA,IAAA,IAI5D;AAAA,IACH,MAAM,SAAS,IAAI;AAAA,EACtB,EAAA,CAAA;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA8D;AAE1D,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,WAAW,mBAAmB,aAAa,EAAE;AAAA,MAC7C,yBAAyB;AAAA,QACvB,QAAQ;AAAA,MACV;AAAA,IAAA;AAAA,EAAA;AAGN;"}
@@ -7,7 +7,7 @@ import { ControlledPromise, NonNullableUpdater, PickAsRequired, Updater } from '
7
7
  import { AnyRouteMatch, MakeRouteMatch, MatchRouteOptions } from './Matches.js';
8
8
  import { ParsedLocation } from './location.js';
9
9
  import { SearchParser, SearchSerializer } from './searchParams.js';
10
- import { BuildLocationFn, CommitLocationOptions, InjectedHtmlEntry, NavigateFn } from './RouterProvider.js';
10
+ import { BuildLocationFn, CommitLocationOptions, NavigateFn } from './RouterProvider.js';
11
11
  import { AnyRedirect, ResolvedRedirect } from './redirects.js';
12
12
  import { NotFoundError } from './not-found.js';
13
13
  import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.js';
@@ -334,7 +334,6 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
334
334
  shouldViewTransition?: boolean;
335
335
  latestLoadPromise: Promise<void>;
336
336
  subscribers: Set<RouterListener<RouterEvent>>;
337
- injectedHtml: Array<InjectedHtmlEntry>;
338
337
  dehydratedData?: TDehydrated;
339
338
  viewTransitionPromise?: ControlledPromise<true>;
340
339
  manifest?: Manifest;
@@ -388,18 +387,13 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
388
387
  cleanCache: () => void;
389
388
  preloadRoute: <TFrom extends string | import('./routeInfo').ParseRoute<TRouteTree, TRouteTree>["fullPath"] = string, TTo extends string = "", TMaskFrom extends string | import('./routeInfo').ParseRoute<TRouteTree, TRouteTree>["fullPath"] = TFrom, TMaskTo extends string = "">(opts: NavigateOptions<Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<Array<AnyRouteMatch> | undefined>;
390
389
  matchRoute: <TFrom extends RoutePaths<TRouteTree> = "/", TTo extends string = "", TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>>(location: ToOptions<Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, TFrom, TTo>, opts?: MatchRouteOptions) => false | RouteById<TRouteTree, TResolved>['types']['allParams'];
390
+ /**
391
+ * @deprecated Injecting HTML directly is no longer supported. Use the new <ScriptOnce /> component instead.
392
+ */
391
393
  injectHtml: (html: string | (() => Promise<string> | string)) => Promise<void>;
392
394
  registeredDeferredsIds: Map<string, {}>;
393
395
  registeredDeferreds: WeakMap<{}, DeferredPromiseState<any>>;
394
396
  getDeferred: (uid: string) => DeferredPromiseState<any> | undefined;
395
- /**
396
- * @deprecated Please inject your own html using the `injectHtml` method
397
- */
398
- dehydrateData: <T>(key: any, getData: T | (() => Promise<T> | T)) => () => T | undefined;
399
- /**
400
- * @deprecated Please extract your own data from scripts injected using the `injectHtml` method
401
- */
402
- hydrateData: <T = unknown>(key: any) => T | undefined;
403
397
  dehydrate: () => DehydratedRouter;
404
398
  hydrate: (__do_not_use_server_ctx?: string) => Promise<void>;
405
399
  handleNotFound: (matches: Array<AnyRouteMatch>, err: NotFoundError) => void;
@@ -1,10 +1,9 @@
1
1
  import { createBrowserHistory, createMemoryHistory } from "@tanstack/history";
2
2
  import { Store } from "@tanstack/react-store";
3
3
  import invariant from "tiny-invariant";
4
- import warning from "tiny-warning";
5
4
  import { rootRouteId } from "./root.js";
6
5
  import { defaultStringifySearch, defaultParseSearch } from "./searchParams.js";
7
- import { createControlledPromise, replaceEqualDeep, pick, last, deepEqual, escapeJSON, functionalUpdate } from "./utils.js";
6
+ import { createControlledPromise, replaceEqualDeep, pick, last, deepEqual, functionalUpdate } from "./utils.js";
8
7
  import { getRouteMatch } from "./RouterProvider.js";
9
8
  import { trimPath, trimPathLeft, parsePathname, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths } from "./path.js";
10
9
  import { isResolvedRedirect, isRedirect } from "./redirects.js";
@@ -30,7 +29,6 @@ class Router {
30
29
  this.shouldViewTransition = void 0;
31
30
  this.latestLoadPromise = Promise.resolve();
32
31
  this.subscribers = /* @__PURE__ */ new Set();
33
- this.injectedHtml = [];
34
32
  this.isServer = typeof document === "undefined";
35
33
  this.startReactTransition = (fn) => fn();
36
34
  this.update = (newOptions) => {
@@ -1147,7 +1145,6 @@ class Router {
1147
1145
  return match;
1148
1146
  };
1149
1147
  this.injectHtml = async (html) => {
1150
- this.injectedHtml.push(html);
1151
1148
  };
1152
1149
  this.registeredDeferredsIds = /* @__PURE__ */ new Map();
1153
1150
  this.registeredDeferreds = /* @__PURE__ */ new WeakMap();
@@ -1158,39 +1155,6 @@ class Router {
1158
1155
  }
1159
1156
  return this.registeredDeferreds.get(token);
1160
1157
  };
1161
- this.dehydrateData = (key, getData) => {
1162
- warning(
1163
- false,
1164
- `The dehydrateData method is deprecated. Please use the injectHtml method to inject your own data.`
1165
- );
1166
- if (typeof document === "undefined") {
1167
- const strKey = typeof key === "string" ? key : JSON.stringify(key);
1168
- this.injectHtml(async () => {
1169
- const id = `__TSR_DEHYDRATED__${strKey}`;
1170
- const data = typeof getData === "function" ? await getData() : getData;
1171
- return `<script id='${id}' suppressHydrationWarning>
1172
- window["__TSR_DEHYDRATED__${escapeJSON(
1173
- strKey
1174
- )}"] = ${JSON.stringify(this.options.transformer.stringify(data))}
1175
- <\/script>`;
1176
- });
1177
- return () => this.hydrateData(key);
1178
- }
1179
- return () => void 0;
1180
- };
1181
- this.hydrateData = (key) => {
1182
- warning(
1183
- false,
1184
- `The hydrateData method is deprecated. Please use the extractHtml method to extract your own data.`
1185
- );
1186
- if (typeof document !== "undefined") {
1187
- const strKey = typeof key === "string" ? key : JSON.stringify(key);
1188
- return this.options.transformer.parse(
1189
- window[`__TSR_DEHYDRATED__${strKey}`]
1190
- );
1191
- }
1192
- return void 0;
1193
- };
1194
1158
  this.dehydrate = () => {
1195
1159
  var _a;
1196
1160
  const pickError = ((_a = this.options.errorSerializer) == null ? void 0 : _a.serialize) ?? defaultSerializeError;