eddev 2.0.0-beta.9 → 2.0.0-beta.91

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.
Files changed (210) hide show
  1. package/dist/app/entry/HydrationOverlay.d.ts +1 -0
  2. package/dist/app/entry/HydrationOverlay.js +2 -0
  3. package/dist/app/entry/MetaTags.d.ts +7 -0
  4. package/dist/app/entry/MetaTags.js +17 -0
  5. package/dist/app/entry/boot-admin.js +11 -6
  6. package/dist/app/entry/hydration-script.d.ts +1 -0
  7. package/dist/app/entry/hydration-script.js +18 -0
  8. package/dist/app/entry/spa-root.js +4 -5
  9. package/dist/app/entry/ssr-root-client.d.ts +3 -1
  10. package/dist/app/entry/ssr-root-client.js +24 -8
  11. package/dist/app/entry/ssr-root.d.ts +5 -4
  12. package/dist/app/entry/ssr-root.js +21 -20
  13. package/dist/app/lib/admin/index.d.ts +2 -2
  14. package/dist/app/lib/admin/index.js +2 -2
  15. package/dist/app/lib/admin/installFieldTypes.js +1 -1
  16. package/dist/app/lib/admin/runWidgets.js +1 -1
  17. package/dist/app/lib/blocks/ContentBlocks.d.ts +1 -1
  18. package/dist/app/lib/blocks/ContentBlocks.js +5 -5
  19. package/dist/app/lib/blocks/EditableText.d.ts +1 -1
  20. package/dist/app/lib/blocks/EditableText.js +3 -3
  21. package/dist/app/lib/blocks/InnerBlocks.d.ts +13 -3
  22. package/dist/app/lib/blocks/InnerBlocks.js +13 -5
  23. package/dist/app/lib/blocks/block-utils.d.ts +2 -2
  24. package/dist/app/lib/blocks/block-utils.js +2 -2
  25. package/dist/app/lib/blocks/editor/EditorHighlights.d.ts +7 -0
  26. package/dist/app/lib/blocks/editor/EditorHighlights.js +130 -0
  27. package/dist/app/lib/blocks/editor/EditorSupport.js +4 -5
  28. package/dist/app/lib/blocks/editor/ErrorBoundaryEditor.d.ts +1 -1
  29. package/dist/app/lib/blocks/editor/editor-config.d.ts +17 -4
  30. package/dist/app/lib/blocks/editor/editor-config.js +21 -9
  31. package/dist/app/lib/blocks/editor/installGutenbergHooks.js +20 -14
  32. package/dist/app/lib/blocks/editor/root-blocks.d.ts +6 -0
  33. package/dist/app/lib/blocks/editor/root-blocks.js +30 -0
  34. package/dist/app/lib/blocks/editor/usePostEditor.d.ts +1 -1
  35. package/dist/app/lib/blocks/index.d.ts +9 -9
  36. package/dist/app/lib/blocks/index.js +9 -9
  37. package/dist/app/lib/blocks/inline-editing.d.ts +1 -1
  38. package/dist/app/lib/blocks/inline-editing.js +7 -5
  39. package/dist/app/lib/devtools/components/BreakpointIndicator.js +1 -1
  40. package/dist/app/lib/devtools/components/DevUI.js +4 -3
  41. package/dist/app/lib/devtools/components/GridIndicator.d.ts +1 -0
  42. package/dist/app/lib/devtools/components/GridIndicator.js +29 -0
  43. package/dist/app/lib/devtools/hooks/usePersistState.d.ts +1 -1
  44. package/dist/app/lib/devtools/hooks/usePersistState.js +11 -2
  45. package/dist/app/lib/devtools/hooks/useTailwind.d.ts +1014 -1014
  46. package/dist/app/lib/devtools/hooks/useTailwind.js +1 -1
  47. package/dist/app/lib/devtools/index.d.ts +1 -1
  48. package/dist/app/lib/devtools/index.js +1 -1
  49. package/dist/app/lib/devtools/loader.js +8 -7
  50. package/dist/app/lib/devtools/useQueryDebug.d.ts +7 -1
  51. package/dist/app/lib/devtools/useQueryDebug.js +5 -8
  52. package/dist/app/lib/dynamic/dynamic.d.ts +1 -1
  53. package/dist/app/lib/dynamic/dynamic.js +5 -1
  54. package/dist/app/lib/dynamic/index.d.ts +1 -1
  55. package/dist/app/lib/dynamic/index.js +1 -1
  56. package/dist/app/lib/hooks/index.d.ts +4 -5
  57. package/dist/app/lib/hooks/index.js +4 -5
  58. package/dist/app/lib/hooks/queryUtils.d.ts +37 -3
  59. package/dist/app/lib/hooks/queryUtils.js +66 -26
  60. package/dist/app/lib/hooks/useAppData.js +1 -1
  61. package/dist/app/lib/hooks/useRPC.d.ts +0 -4
  62. package/dist/app/lib/hooks/useRPC.js +1 -8
  63. package/dist/app/lib/internal/finalize-rpc.d.ts +17 -0
  64. package/dist/app/lib/internal/finalize-rpc.js +3 -0
  65. package/dist/app/lib/internal/index.d.ts +5 -4
  66. package/dist/app/lib/internal/index.js +5 -4
  67. package/dist/app/lib/internal/read-admin-manifest.d.ts +1 -1
  68. package/dist/app/lib/legacy-stitches/createStitches.d.ts +21 -21
  69. package/dist/app/lib/legacy-stitches/createStitches.js +1 -1
  70. package/dist/app/lib/legacy-stitches/index.d.ts +1 -1
  71. package/dist/app/lib/legacy-stitches/index.js +1 -1
  72. package/dist/app/lib/routing/components/BackButton.d.ts +49 -0
  73. package/dist/app/lib/routing/components/BackButton.js +47 -0
  74. package/dist/app/lib/routing/components/BrowserRouter.d.ts +4 -1
  75. package/dist/app/lib/routing/components/BrowserRouter.js +95 -19
  76. package/dist/app/lib/routing/components/ClientOnly.d.ts +1 -1
  77. package/dist/app/lib/routing/components/ClientOnly.js +1 -1
  78. package/dist/app/lib/routing/components/Link.d.ts +1 -0
  79. package/dist/app/lib/routing/components/Link.js +11 -12
  80. package/dist/app/lib/routing/components/RouteRenderer.d.ts +1 -1
  81. package/dist/app/lib/routing/components/RouteRenderer.js +7 -6
  82. package/dist/app/lib/routing/components/SSRRouter.d.ts +2 -2
  83. package/dist/app/lib/routing/components/SSRRouter.js +5 -6
  84. package/dist/app/lib/routing/components/ScrollRestoration.js +5 -2
  85. package/dist/app/lib/routing/context.d.ts +8 -5
  86. package/dist/app/lib/routing/context.js +13 -96
  87. package/dist/app/lib/routing/hooks/useRestorableState.d.ts +2 -1
  88. package/dist/app/lib/routing/hooks/useRestorableState.js +2 -1
  89. package/dist/app/lib/routing/hooks/useRoute.d.ts +16 -1
  90. package/dist/app/lib/routing/hooks/useRoute.js +22 -1
  91. package/dist/app/lib/routing/hooks/useRouteMeta.d.ts +5 -0
  92. package/dist/app/lib/routing/hooks/useRouteMeta.js +9 -0
  93. package/dist/app/lib/routing/hooks/useRouteTransition.d.ts +1 -1
  94. package/dist/app/lib/routing/hooks/useRouteTransition.js +1 -1
  95. package/dist/app/lib/routing/hooks/useRouter.d.ts +1 -1
  96. package/dist/app/lib/routing/hooks/useRouter.js +1 -1
  97. package/dist/app/lib/routing/hooks/useRouterEvents.d.ts +1 -1
  98. package/dist/app/lib/routing/hooks/useRouterEvents.js +1 -1
  99. package/dist/app/lib/routing/hooks/useRouterState.d.ts +1 -1
  100. package/dist/app/lib/routing/hooks/useRouterState.js +1 -1
  101. package/dist/app/lib/routing/hooks/useSearchParams.js +2 -2
  102. package/dist/app/lib/routing/index.d.ts +14 -13
  103. package/dist/app/lib/routing/index.js +14 -13
  104. package/dist/app/lib/routing/loader.d.ts +2 -2
  105. package/dist/app/lib/routing/loader.js +20 -11
  106. package/dist/app/lib/routing/types.d.ts +36 -10
  107. package/dist/app/lib/routing/utils.d.ts +5 -2
  108. package/dist/app/lib/routing/utils.js +37 -4
  109. package/dist/app/lib/{hooks → runtime}/apiConfig.d.ts +6 -2
  110. package/dist/app/lib/runtime/apiConfig.js +6 -0
  111. package/dist/app/lib/runtime/errorHandling.d.ts +39 -0
  112. package/dist/app/lib/runtime/errorHandling.js +6 -0
  113. package/dist/app/lib/runtime/index.d.ts +2 -0
  114. package/dist/app/lib/runtime/index.js +2 -0
  115. package/dist/app/lib/views/index.d.ts +1 -1
  116. package/dist/app/lib/views/index.js +1 -1
  117. package/dist/app/server/defineRouter.d.ts +2 -0
  118. package/dist/app/server/defineRouter.js +4 -0
  119. package/dist/app/server/index.d.ts +5 -3
  120. package/dist/app/server/index.js +5 -3
  121. package/dist/app/server/proxy-wp-admin.d.ts +1 -2
  122. package/dist/app/server/proxy-wp-admin.js +32 -14
  123. package/dist/app/server/render-ssr-page.d.ts +21 -2
  124. package/dist/app/server/render-ssr-page.js +143 -11
  125. package/dist/app/server/rpc.d.ts +56 -0
  126. package/dist/app/server/rpc.js +18 -0
  127. package/dist/app/server/server-context.d.ts +42 -4
  128. package/dist/app/server/server-context.js +196 -30
  129. package/dist/app/server/utils/replace-host.d.ts +1 -1
  130. package/dist/app/server/utils/replace-host.js +10 -2
  131. package/dist/app/server/utils/swr-cache.d.ts +4 -0
  132. package/dist/app/server/utils/swr-cache.js +31 -0
  133. package/dist/app/utils/APIProvider.d.ts +2 -0
  134. package/dist/app/utils/APIProvider.js +5 -0
  135. package/dist/app/utils/BlockErrorBoundary.d.ts +19 -0
  136. package/dist/app/utils/BlockErrorBoundary.js +38 -0
  137. package/dist/app/utils/ErrorMessage.d.ts +5 -0
  138. package/dist/app/utils/ErrorMessage.js +14 -0
  139. package/dist/app/utils/RouteErrorBoundary.d.ts +18 -0
  140. package/dist/app/utils/RouteErrorBoundary.js +38 -0
  141. package/dist/app/utils/asset-capture.d.ts +2 -0
  142. package/dist/app/utils/asset-capture.js +5 -0
  143. package/dist/app/utils/hydration-debugger.d.ts +13 -0
  144. package/dist/app/utils/hydration-debugger.js +11 -0
  145. package/dist/app/utils/query-client.d.ts +2 -0
  146. package/dist/app/utils/query-client.js +5 -1
  147. package/dist/app/utils/trpc-client.d.ts +2 -0
  148. package/dist/app/utils/trpc-client.js +39 -0
  149. package/dist/node/cli/cli-worker.js +10 -5
  150. package/dist/node/cli/cli.js +79 -11
  151. package/dist/node/cli/display/CLIApp.js +3 -6
  152. package/dist/node/cli/display/boot-cli-app.js +1 -1
  153. package/dist/node/cli/display/tools/CreateBlock.d.ts +1 -1
  154. package/dist/node/cli/display/tools/cli-tools.d.ts +1 -11
  155. package/dist/node/cli/display/tools/cli-tools.js +9 -9
  156. package/dist/node/cli/version.d.ts +1 -1
  157. package/dist/node/cli/version.js +1 -1
  158. package/dist/node/compiler/build-vinxi.js +3 -1
  159. package/dist/node/compiler/bundler.admin.d.ts +1 -1
  160. package/dist/node/compiler/bundler.admin.js +1 -1
  161. package/dist/node/compiler/bundler.frontend.js +1 -1
  162. package/dist/node/compiler/dev-server.js +10 -0
  163. package/dist/node/compiler/get-vite-config.d.ts +1 -0
  164. package/dist/node/compiler/get-vite-config.js +34 -11
  165. package/dist/node/compiler/vinxi-app.d.ts +12 -0
  166. package/dist/node/compiler/vinxi-app.js +139 -32
  167. package/dist/node/compiler/vinxi-codegen.js +321 -108
  168. package/dist/node/graphql/graphql-codegen.d.ts +11 -1
  169. package/dist/node/graphql/graphql-codegen.js +210 -33
  170. package/dist/node/graphql/graphql-schema-loader.d.ts +2 -1
  171. package/dist/node/graphql/graphql-schema-loader.js +5 -16
  172. package/dist/node/graphql/plugins/gql-plugin-queries.js +1 -1
  173. package/dist/node/graphql/query-files-loader.d.ts +3 -0
  174. package/dist/node/graphql/query-files-loader.js +5 -0
  175. package/dist/node/project/config.d.ts +159 -73
  176. package/dist/node/project/config.js +69 -20
  177. package/dist/node/project/env.d.ts +4 -0
  178. package/dist/node/project/env.js +1 -0
  179. package/dist/node/project/manifest/block-manifest.js +1 -0
  180. package/dist/node/project/manifest/manifest.d.ts +1 -0
  181. package/dist/node/project/manifest/manifest.js +14 -10
  182. package/dist/node/project/manifest/routes-manifest.d.ts +20 -0
  183. package/dist/node/project/manifest/routes-manifest.js +74 -0
  184. package/dist/node/project/manifest/view-manifest.js +1 -1
  185. package/dist/node/project/project.d.ts +9 -1
  186. package/dist/node/project/project.js +37 -6
  187. package/dist/node/project/wp-info.d.ts +1 -0
  188. package/dist/node/project/wp-info.js +13 -1
  189. package/dist/node/types/block-type.d.ts +25 -20
  190. package/dist/node/types/block-type.js +1 -0
  191. package/dist/node/types/view-type.d.ts +7 -7
  192. package/dist/node/utils/fetch-wp.d.ts +1 -0
  193. package/dist/node/utils/fetch-wp.js +27 -0
  194. package/dist/node/utils/fs-codegen.d.ts +2 -0
  195. package/dist/node/utils/fs-codegen.js +2 -1
  196. package/dist/node/utils/is-deploying.js +1 -1
  197. package/dist/node/utils/stateful-log.js +2 -0
  198. package/dist/node/utils/watch-file-tree.d.ts +17 -3
  199. package/dist/node/utils/watch-file-tree.js +12 -5
  200. package/package.json +17 -13
  201. package/types.app.d.ts +4 -2
  202. package/types.app.internal.d.ts +2 -2
  203. package/types.node.d.ts +3 -3
  204. package/dist/app/lib/blocks/ErrorBoundaryFrontend.d.ts +0 -15
  205. package/dist/app/lib/blocks/ErrorBoundaryFrontend.js +0 -35
  206. package/dist/app/lib/hooks/apiConfig.js +0 -4
  207. package/dist/app/lib/hooks/usePageLoad.d.ts +0 -6
  208. package/dist/app/lib/hooks/usePageLoad.js +0 -5
  209. package/dist/app/server/utils/index.html.d.ts +0 -2
  210. package/dist/app/server/utils/index.html.js +0 -14
@@ -0,0 +1,47 @@
1
+ import { useMemo } from "react";
2
+ import { useRoute } from "../hooks/useRoute";
3
+ import { useRouter } from "../hooks/useRouter";
4
+ import { useRouterState } from "../hooks/useRouterState";
5
+ import { getLinkHandlerMode } from "../utils";
6
+ /**
7
+ * Display a back button that will navigate to the previous page in the router's history.
8
+ *
9
+ * This will allow you to render a back button on the condition that the back button will not send the user to a different website.
10
+ */
11
+ export function BackButton(props) {
12
+ const router = useRouter();
13
+ const prevRoute = useRouterState((state) => state.history[state.history.length - 2]);
14
+ const contextRoute = useRoute();
15
+ const activeRoute = useRouterState((state) => state.activeRoute);
16
+ const route = props.mode === "global" ? activeRoute : contextRoute;
17
+ const backAction = useMemo(() => {
18
+ if (prevRoute && (!props.filter || props.filter(prevRoute))) {
19
+ return (e) => {
20
+ const { mode } = getLinkHandlerMode(e, prevRoute.uri);
21
+ if (mode === "navigate") {
22
+ e.preventDefault();
23
+ history.back();
24
+ // history.length
25
+ }
26
+ else if (mode === "ignore") {
27
+ e.preventDefault();
28
+ }
29
+ };
30
+ }
31
+ else if (props.fallbackHref) {
32
+ return (e) => {
33
+ const { mode } = getLinkHandlerMode(e, props.fallbackHref);
34
+ if (mode === "navigate") {
35
+ e.preventDefault();
36
+ router.navigate(props.fallbackHref);
37
+ }
38
+ else if (mode === "ignore") {
39
+ e.preventDefault();
40
+ }
41
+ };
42
+ }
43
+ }, [route, props.filter, props.fallbackHref]);
44
+ if (backAction) {
45
+ return props.render ? props.render({ route: prevRoute, onClick: backAction }) : null;
46
+ }
47
+ }
@@ -1,4 +1,7 @@
1
1
  import { PropsWithChildren } from "react";
2
- type Props = PropsWithChildren<{}>;
2
+ import { type RouterAPI } from "../types.js";
3
+ type Props = PropsWithChildren<{
4
+ routerRef?: React.MutableRefObject<RouterAPI | null>;
5
+ }>;
3
6
  export declare function BrowserRouter(props: Props): import("react/jsx-runtime").JSX.Element;
4
7
  export {};
@@ -1,11 +1,20 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState, useTransition } from "react";
3
- import { isRelative, parseURL, resolveURL } from "ufo";
4
- import { RouterContext, RouterStateContext } from "../context";
5
- import { RouteLoader } from "../loader";
6
- import { getLinkHandlerMode, normalizeRoute, parseQuery, stringifyRouteLink } from "../utils";
7
- import { AppRenderer } from "./RouteRenderer";
3
+ import { isEqual, isRelative, parseURL, resolveURL } from "ufo";
4
+ import { clientMetaTags, RouterContext, RouterStateContext } from "../context.js";
5
+ import { $routeMetaStore } from "../hooks/useRouteMeta.js";
6
+ import { RouteLoader } from "../loader.js";
7
+ import { getLinkHandlerMode, getRouteMeta, isSamePathname, normalizeRoute, parseQuery, stringifyRouteLink, } from "../utils.js";
8
+ import { AppRenderer } from "./RouteRenderer.js";
9
+ // Create a global RouteLoader instance
8
10
  const loader = new RouteLoader();
11
+ // Create a unique ID for each history entry
12
+ let historyStamp = String(new Date().getTime());
13
+ let historyIndex = 0;
14
+ function getHistoryId() {
15
+ return historyStamp + historyIndex++;
16
+ }
17
+ // Set up the initial route data
9
18
  let initialRoute;
10
19
  let initialRouteHydrated = false;
11
20
  if (env.client && !env.admin) {
@@ -23,7 +32,10 @@ if (env.client && !env.admin) {
23
32
  search: "",
24
33
  query: {},
25
34
  view: initialData.view,
35
+ meta: getRouteMeta(initialData),
26
36
  });
37
+ history.replaceState(historyStateForRoute(initialRoute), "", document.location.href);
38
+ $routeMetaStore.data = getRouteMeta(initialData);
27
39
  }
28
40
  function parseHrefPath(url) {
29
41
  if (isRelative(url)) {
@@ -54,14 +66,9 @@ function historyStateForRoute(route) {
54
66
  state: route.returnState,
55
67
  };
56
68
  }
57
- let index = 0;
58
- function getHistoryId() {
59
- return String(index++);
60
- }
61
69
  let lastRouterState = null;
62
70
  export function BrowserRouter(props) {
63
71
  const pendingRoute = useRef(null);
64
- // const [activeRoute, setActiveRoute] = useState<RouteState>(initialRoute)
65
72
  const [transitioning, startTransition] = useTransition();
66
73
  const [routerState, setRouterState] = useState(() => ({
67
74
  activeRoute: initialRoute,
@@ -79,6 +86,16 @@ export function BrowserRouter(props) {
79
86
  ...state,
80
87
  ...update,
81
88
  };
89
+ if (state?.activeRoute?.meta?.tags) {
90
+ if (env.serverless) {
91
+ clientMetaTags.setMetaTags(state.activeRoute.meta.tags ?? []);
92
+ }
93
+ else {
94
+ const title = state.activeRoute.meta.tags.find((tag) => tag.tagName === "title")?.inner;
95
+ if (title)
96
+ document.title = title;
97
+ }
98
+ }
82
99
  setRouterState(state);
83
100
  };
84
101
  const internals = {
@@ -181,11 +198,20 @@ export function BrowserRouter(props) {
181
198
  });
182
199
  if (cancelled)
183
200
  return;
184
- const data = await loader.loadRouteData(parseHrefPath(args.url));
185
- if (!data.view) {
186
- console.error("No `view` property in route data");
187
- return;
188
- }
201
+ const data = await loader.loadRouteData(parseHrefPath(args.url)).catch((err) => {
202
+ emitEvent({ type: "error", error: err, critical: true });
203
+ return {
204
+ view: "_error",
205
+ viewType: "react",
206
+ appData: loader.appData,
207
+ viewData: {
208
+ data: {
209
+ code: 500,
210
+ error: err,
211
+ },
212
+ },
213
+ };
214
+ });
189
215
  const lazyComponent = loader.getRouteComponent(data.view);
190
216
  if (!lazyComponent) {
191
217
  console.error(`No component found for view: ${data.view}`);
@@ -196,11 +222,12 @@ export function BrowserRouter(props) {
196
222
  hash: link.hash,
197
223
  search: "",
198
224
  query: link.query,
199
- pathname: link.pathname,
225
+ pathname: data.canonical ?? link.pathname,
200
226
  view: data.view,
201
227
  props: data.viewData?.data ?? {},
202
228
  component: lazyComponent,
203
229
  returnState: args.restoreState ?? {},
230
+ meta: getRouteMeta(data),
204
231
  });
205
232
  setState({
206
233
  pendingRoute: route,
@@ -229,6 +256,7 @@ export function BrowserRouter(props) {
229
256
  lastRoute: currentRoute,
230
257
  link,
231
258
  });
259
+ $routeMetaStore.data = route.meta;
232
260
  };
233
261
  startTransition(() => {
234
262
  pendingRoute.current = route;
@@ -247,6 +275,9 @@ export function BrowserRouter(props) {
247
275
  goingBack: false,
248
276
  });
249
277
  },
278
+ getState() {
279
+ return state;
280
+ },
250
281
  replaceHash(hash) {
251
282
  replaceRoute({
252
283
  ...getActiveRoute(),
@@ -257,6 +288,7 @@ export function BrowserRouter(props) {
257
288
  replaceRoute({
258
289
  ...getActiveRoute(),
259
290
  query,
291
+ returnState: captureState(),
260
292
  });
261
293
  },
262
294
  async prefetch(url) {
@@ -265,7 +297,7 @@ export function BrowserRouter(props) {
265
297
  if (loader.hasRouteData(link.pathname))
266
298
  return;
267
299
  emitEvent({ type: "preload:start", currentRoute: getActiveRoute(), link });
268
- const data = await loader.loadRouteData(link.pathname).then((data) => {
300
+ await loader.loadRouteData(link.pathname).then((data) => {
269
301
  emitEvent({ type: "preload:data-ready", currentRoute: getActiveRoute(), link, data });
270
302
  });
271
303
  }
@@ -297,8 +329,8 @@ export function BrowserRouter(props) {
297
329
  subscribers.delete(fn);
298
330
  };
299
331
  },
300
- handleClickEvent(e, originalHref) {
301
- const { mode, href } = getLinkHandlerMode(e, originalHref);
332
+ handleClickEvent(e, originalHref, preferBack) {
333
+ const { mode, href } = getLinkHandlerMode(e, originalHref, state.activeRoute);
302
334
  if (mode === "ignore") {
303
335
  e.preventDefault();
304
336
  return;
@@ -308,10 +340,53 @@ export function BrowserRouter(props) {
308
340
  }
309
341
  else if (mode === "navigate" && href) {
310
342
  e.preventDefault();
343
+ if (preferBack) {
344
+ const lastState = state.history.length > 1 && state.history[state.history.length - 2];
345
+ if (lastState) {
346
+ const doesMatch = preferBack === "exact" ? isEqual(href, lastState.uri) : isSamePathname(href, lastState.uri);
347
+ if (doesMatch) {
348
+ history.back();
349
+ return;
350
+ }
351
+ }
352
+ }
311
353
  api.navigate(href);
312
354
  }
313
355
  },
314
356
  emitEvent,
357
+ restoreRoute(route) {
358
+ const stack = state.history;
359
+ // Is the route in our history stack? (going back)
360
+ const index = stack.findIndex((item) => item.id === route.id);
361
+ if (index >= 0) {
362
+ return doRouteTransition({
363
+ url: route.uri,
364
+ route,
365
+ goingBack: true,
366
+ history: stack.slice(0, index),
367
+ restoreState: route.returnState,
368
+ shouldPush: false,
369
+ });
370
+ }
371
+ // Is the route in our history _cache_? (probably going forward)
372
+ if (historyCache.has(route.id)) {
373
+ return doRouteTransition({
374
+ url: route.uri,
375
+ route,
376
+ goingBack: false,
377
+ history: stack,
378
+ restoreState: route.returnState,
379
+ shouldPush: false,
380
+ });
381
+ }
382
+ return doRouteTransition({
383
+ url: route.uri,
384
+ goingBack: false,
385
+ history: stack,
386
+ restoreState: route.returnState,
387
+ shouldPush: false,
388
+ });
389
+ },
315
390
  };
316
391
  return {
317
392
  api,
@@ -340,6 +415,7 @@ export function BrowserRouter(props) {
340
415
  // Handle popState
341
416
  // const router = useRouterStore.getState()
342
417
  const onPopState = (e) => {
418
+ // console.log("Popped", e.state)
343
419
  internals.poppedState?.(document.location.href, e.state ?? {});
344
420
  };
345
421
  window.addEventListener("popstate", onPopState);
@@ -8,5 +8,5 @@ type Props = PropsWithChildren<{
8
8
  *
9
9
  * The optional 'fallback' prop can be used to show a loading state or placeholder content while the client bundle is loading.
10
10
  */
11
- export declare function ClientOnly(props: Props): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | null;
11
+ export declare function ClientOnly(props: Props): string | number | boolean | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element | null;
12
12
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Fragment } from "react";
3
- import { useIsSSR } from "../hooks/useIsSSR";
3
+ import { useIsSSR } from "../hooks/useIsSSR.js";
4
4
  /**
5
5
  * Renders children, but only on the client.
6
6
  *
@@ -3,6 +3,7 @@ type Props<T extends ElementType = "a"> = NoInfer<Omit<ComponentPropsWithRef<T>,
3
3
  href?: string | null;
4
4
  target?: string | null;
5
5
  as?: T;
6
+ preferBack?: boolean | "exact";
6
7
  };
7
8
  export declare const Link: <T extends ElementType = "a">(props: Props<T>) => ReactElement;
8
9
  /**
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useMemo } from "react";
3
3
  import { parseURL, resolveURL, withoutTrailingSlash } from "ufo";
4
- import { useIsSSR } from "../hooks/useIsSSR";
5
- import { useRouter } from "../hooks/useRouter";
6
- import { isSameOrigin } from "../utils";
7
- import { useRoute } from "../hooks/useRoute";
8
- import { useRouterState } from "../hooks/useRouterState";
9
- export const Link = forwardRef((props, ref) => {
10
- const Comp = props.as || "a";
4
+ import { useIsSSR } from "../hooks/useIsSSR.js";
5
+ import { useRouter } from "../hooks/useRouter.js";
6
+ import { addTrailingSlash, isSameOrigin } from "../utils.js";
7
+ import { useRoute } from "../hooks/useRoute.js";
8
+ import { useRouterState } from "../hooks/useRouterState.js";
9
+ export const Link = forwardRef(({ preferBack, as, ...props }, ref) => {
10
+ const Comp = as || "a";
11
11
  if (env.admin) {
12
12
  return (_jsx(Comp, { ref: ref, ...props, href: props.href ?? undefined, onClick: (e) => {
13
13
  props.onClick?.(e);
@@ -15,17 +15,16 @@ export const Link = forwardRef((props, ref) => {
15
15
  } }));
16
16
  }
17
17
  else {
18
- const preload = useRouter((r) => r.preload);
19
- const handleClickEvent = useRouter((r) => r.handleClickEvent);
18
+ const router = useRouter();
20
19
  const state = useLinkState(props.href ?? "");
21
- return (_jsx(Comp, { ref: ref, "data-active": state.active ?? undefined, "data-child-active": state.childActive ?? undefined, "data-pending": state.pending ?? undefined, ...props, href: props.href ?? undefined, onMouseEnter: (e) => {
20
+ return (_jsx(Comp, { ref: ref, "data-active": state.active ?? undefined, "data-child-active": state.childActive ?? undefined, "data-pending": state.pending ?? undefined, ...props, href: addTrailingSlash(props.href), onMouseEnter: (e) => {
22
21
  if (props.onMouseEnter) {
23
22
  props.onMouseEnter(e);
24
23
  }
25
- preload(props.href);
24
+ router.preload(props.href);
26
25
  }, onClick: (e) => {
27
26
  props.onClick?.(e);
28
- handleClickEvent(e, props.href ?? undefined);
27
+ router.handleClickEvent(e, props.href ?? undefined, preferBack);
29
28
  } }));
30
29
  }
31
30
  });
@@ -1,4 +1,4 @@
1
- import { RouteState } from "../types";
1
+ import { RouteState } from "../types.js";
2
2
  export declare const AppRenderer: import("react").MemoExoticComponent<() => import("react/jsx-runtime").JSX.Element>;
3
3
  export declare function MainRoute(): import("react/jsx-runtime").JSX.Element;
4
4
  export declare function RouteDisplay(props: {
@@ -1,15 +1,16 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { memo, Suspense, useMemo } from "react";
3
- import { RouteItemContext } from "../context";
4
- import { useRouter } from "../hooks/useRouter";
5
- import { useRouterState } from "../hooks/useRouterState";
2
+ import { memo, useMemo } from "react";
3
+ import { RouteErrorBoundary } from "../../../utils/RouteErrorBoundary.js";
4
+ import { RouteItemContext } from "../context.js";
5
+ import { useRouter } from "../hooks/useRouter.js";
6
+ import { useRouterState } from "../hooks/useRouterState.js";
6
7
  export const AppRenderer = memo(() => {
7
8
  const { appData, appComponent: AppComponent } = useRouter().loader;
8
9
  const { activeRoute } = useRouterState();
9
10
  const app = useMemo(() => {
10
11
  return (_jsx(AppComponent, { ...appData, children: _jsx(MainRoute, {}) }));
11
12
  }, [AppComponent, appData]);
12
- return (_jsx(Suspense, { children: _jsx(RouteItemContext.Provider, { value: activeRoute, children: app }) }));
13
+ return _jsx(RouteItemContext.Provider, { value: activeRoute, children: app });
13
14
  });
14
15
  export function MainRoute() {
15
16
  const activeRoute = useRouterState((s) => s.activeRoute);
@@ -22,7 +23,7 @@ export function RouteDisplay(props) {
22
23
  }
23
24
  return useMemo(() => {
24
25
  let child = !!Component && _jsx(Component, { ...props.route.props });
25
- return _jsx(RouteItemContext.Provider, { value: props.route, children: child });
26
+ return (_jsx(RouteErrorBoundary, { route: props.route, children: _jsx(RouteItemContext.Provider, { value: props.route, children: child }) }));
26
27
  }, [Component, props.route, props.route]);
27
28
  }
28
29
  RouteDisplay.displayName = "RouteDisplay";
@@ -1,6 +1,6 @@
1
1
  import { PropsWithChildren } from "react";
2
- import { RouteLoader } from "../loader";
3
- import { RouteState } from "../types";
2
+ import { RouteLoader } from "../loader.js";
3
+ import { RouteState } from "../types.js";
4
4
  type Props = PropsWithChildren<{
5
5
  route: RouteState;
6
6
  loader: RouteLoader;
@@ -1,14 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Suspense } from "react";
3
- import { RouterContext, RouterStateContext } from "../context";
4
- import { useRouter } from "../hooks/useRouter";
5
- import { useRouterState } from "../hooks/useRouterState";
6
- import { AppRenderer } from "./RouteRenderer";
2
+ import { RouterContext, RouterStateContext } from "../context.js";
3
+ import { useRouter } from "../hooks/useRouter.js";
4
+ import { useRouterState } from "../hooks/useRouterState.js";
5
+ import { AppRenderer } from "./RouteRenderer.js";
7
6
  export function SSRRouter(props) {
8
7
  const router = useRouter();
9
8
  const routerState = useRouterState();
10
9
  router.loader = props.loader;
11
10
  routerState.history = [props.route];
12
11
  routerState.activeRoute = props.route;
13
- return (_jsx(Suspense, { children: _jsx(RouterContext.Provider, { value: router, children: _jsx(RouterStateContext.Provider, { value: routerState, children: _jsx(AppRenderer, {}) }) }) }));
12
+ return (_jsx(RouterContext.Provider, { value: router, children: _jsx(RouterStateContext.Provider, { value: routerState, children: _jsx(AppRenderer, {}) }) }));
14
13
  }
@@ -1,4 +1,4 @@
1
- import { useRouterEvents } from "../hooks/useRouterEvents";
1
+ import { useRouterEvents } from "../hooks/useRouterEvents.js";
2
2
  /**
3
3
  * Enables scroll restoration when navigation backwards, as well as resetting scroll position when navigating forwards.
4
4
  */
@@ -11,7 +11,10 @@ export function ScrollRestoration(props) {
11
11
  }));
12
12
  useRouterEvents((event) => {
13
13
  if (event.type === "navigate:changed") {
14
- // console.log("Changed! Restoring scroll", event.currentRoute)
14
+ // If the pathname and search term are the same, then we're on the same page
15
+ const isSameRoute = event.currentRoute.pathname === event.lastRoute.pathname && event.currentRoute.search === event.lastRoute.search;
16
+ if (isSameRoute)
17
+ return;
15
18
  if (event.currentRoute.returnState) {
16
19
  restore({
17
20
  top: event.currentRoute.returnState.scrollTop ?? 0,
@@ -1,5 +1,8 @@
1
- import { Context } from "react";
2
- import { RouterAPI, RouterAPIState } from "./types";
3
- export declare const RouterContext: Context<RouterAPI>;
4
- export declare const RouterStateContext: Context<RouterAPIState>;
5
- export declare const RouteItemContext: Context<import("./types").TypedRouteState<"_unknown", {}>>;
1
+ import { RouteMetaTag, RouterAPI, RouterAPIState } from "./types.js";
2
+ export declare const RouterContext: import("react").Context<RouterAPI>;
3
+ export declare const RouterStateContext: import("react").Context<RouterAPIState>;
4
+ export declare const RouteItemContext: import("react").Context<import("./types.js").TypedRouteState<"_unknown", {}>>;
5
+ export declare const clientMetaTags: {
6
+ tags: null | RouteMetaTag[];
7
+ setMetaTags(tags: RouteMetaTag[]): void;
8
+ };
@@ -1,5 +1,6 @@
1
1
  import { createContext } from "react";
2
- import { RouteLoader } from "./loader";
2
+ import { RouteLoader } from "./loader.js";
3
+ import { proxy } from "valtio";
3
4
  const NOOP_ROUTE = {
4
5
  component: () => null,
5
6
  id: "initial",
@@ -12,6 +13,7 @@ const NOOP_ROUTE = {
12
13
  search: "",
13
14
  query: {},
14
15
  returnState: undefined,
16
+ meta: {},
15
17
  };
16
18
  export const RouterContext = createContext({
17
19
  loader: new RouteLoader(),
@@ -25,6 +27,10 @@ export const RouterContext = createContext({
25
27
  replaceQuery(query) { },
26
28
  handleClickEvent(e, originalHref) { },
27
29
  emitEvent(event) { },
30
+ getState() {
31
+ return null;
32
+ },
33
+ restoreRoute(route) { },
28
34
  });
29
35
  export const RouterStateContext = createContext({
30
36
  history: [NOOP_ROUTE],
@@ -32,98 +38,9 @@ export const RouterStateContext = createContext({
32
38
  blockers: [],
33
39
  });
34
40
  export const RouteItemContext = createContext(NOOP_ROUTE);
35
- // type StoreHook<State> = <Slice = State>(
36
- // selector?: (state: State) => Slice,
37
- // areEqual?: (a: Slice, b: Slice) => boolean,
38
- // ) => Slice
39
- // type Store<T> = {
40
- // subscribe(sub: (value: T) => void): () => void
41
- // value: T
42
- // update(next: T): void
43
- // }
44
- // function createStore<T>(initial: T): Store<T> {
45
- // let value = initial
46
- // const subscribers = new Set<(value: T) => void>()
47
- // return {
48
- // subscribe(sub: (value: T) => void) {
49
- // subscribers.add(sub)
50
- // return () => {
51
- // subscribers.delete(sub)
52
- // }
53
- // },
54
- // get value() {
55
- // return value
56
- // },
57
- // update(nextValue: T) {
58
- // value = nextValue
59
- // if (subscribers.size) {
60
- // console.log("UPDATE", value)
61
- // startTransition(() => {
62
- // for (let sub of subscribers) {
63
- // sub(value)
64
- // }
65
- // })
66
- // }
67
- // },
68
- // }
69
- // }
70
- // export function createStoreHook<T>(store: Store<T>): StoreHook<T> {
71
- // const hook = (selector: any) => {
72
- // const get = () => (selector ? selector(store.value) : store.value)
73
- // return useSyncExternalStore(store.subscribe, get, get)
74
- // }
75
- // return hook as StoreHook<T>
76
- // }
77
- // export function createStoreContextHook<T>(ctx: Context<Store<T>>): StoreHook<T> {
78
- // const hook = (selector: any) => {
79
- // const store = useContext(ctx)
80
- // const get = () => (selector ? selector(store.value) : store.value)
81
- // return useSyncExternalStore(store.subscribe, get, get)
82
- // }
83
- // return hook as StoreHook<T>
84
- // }
85
- // export const RouterContext = createContext<Store<RouterAPI>>(null!)
86
- // export const RouterStateContext = createContext<Store<RouterAPIState>>(null!)
87
- // export const RouteContext = createContext<Store<RouteState>>(null!)
88
- // const NOOP_ROUTE: RouteState = {
89
- // component: () => null,
90
- // id: "initial",
91
- // hash: "",
92
- // key: "initial",
93
- // pathname: "",
94
- // props: {},
95
- // uri: "",
96
- // view: "_unknown",
97
- // search: "",
98
- // query: {},
99
- // returnState: undefined,
100
- // }
101
- // export const createRouteItemStore = (initial?: RouteState) => {
102
- // return createStore<RouteState>(initial ?? NOOP_ROUTE)
103
- // }
104
- // export function createRouterAPIStore(initial?: RouterAPI) {
105
- // return createStore<RouterAPI>(
106
- // initial ?? {
107
- // loader: new RouteLoader(),
108
- // async navigate(url) {},
109
- // async prefetch(url) {},
110
- // async preload(url) {},
111
- // subscribe(fn) {
112
- // return () => {}
113
- // },
114
- // replaceHash(hash) {},
115
- // replaceQuery(query) {},
116
- // handleClickEvent(e, originalHref) {},
117
- // emitEvent(event) {},
118
- // },
119
- // )
120
- // }
121
- // export function createRouterStateStore(initial?: RouterAPIState) {
122
- // return createStore<RouterAPIState>(
123
- // initial ?? {
124
- // history: [],
125
- // activeRoute: NOOP_ROUTE,
126
- // blockers: [],
127
- // },
128
- // )
129
- // }
41
+ export const clientMetaTags = proxy({
42
+ tags: null,
43
+ setMetaTags(tags) {
44
+ clientMetaTags.tags = tags;
45
+ },
46
+ });
@@ -1,5 +1,6 @@
1
+ import { Dispatch } from "react";
1
2
  /**
2
3
  * Works exactly like useState, but allows back and forward navigation to restore the previous state.
3
4
  * You must pass a unique ID as an additional first parameter to ensure the state is restored correctly.
4
5
  */
5
- export declare function useRestorableState<T>(key: string, fallback?: T): any[];
6
+ export declare function useRestorableState<T>(key: string, fallback: T): [T, Dispatch<T>];
@@ -1,5 +1,6 @@
1
1
  import { useState } from "react";
2
- import { useRoute, useRouterEvents } from "..";
2
+ import { useRouterEvents } from "./useRouterEvents.js";
3
+ import { useRoute } from "./useRoute.js";
3
4
  /**
4
5
  * Works exactly like useState, but allows back and forward navigation to restore the previous state.
5
6
  * You must pass a unique ID as an additional first parameter to ensure the state is restored correctly.
@@ -1,2 +1,17 @@
1
- import { RouteState } from "../types";
1
+ import type { RouteState } from "../types.js";
2
+ /**
3
+ * Returns the current route object.
4
+ *
5
+ * In most circumstances, this will be the active top-level route.
6
+ *
7
+ * In cases where manual rendering of routes is taking place, such as during page transitions or in some modal cases.
8
+ *
9
+ * @returns The current route
10
+ */
2
11
  export declare function useRoute(): RouteState;
12
+ /**
13
+ * Returns the current route, if it matches the specified view, otherwise null.
14
+ */
15
+ export declare function useViewRoute<V extends keyof ViewProps>(view: V): Extract<RouteState, {
16
+ view: V;
17
+ }> | null;
@@ -1,5 +1,26 @@
1
1
  import { useContext } from "react";
2
- import { RouteItemContext } from "../context";
2
+ import { RouteItemContext } from "../context.js";
3
+ /**
4
+ * Returns the current route object.
5
+ *
6
+ * In most circumstances, this will be the active top-level route.
7
+ *
8
+ * In cases where manual rendering of routes is taking place, such as during page transitions or in some modal cases.
9
+ *
10
+ * @returns The current route
11
+ */
3
12
  export function useRoute() {
4
13
  return useContext(RouteItemContext);
5
14
  }
15
+ /**
16
+ * Returns the current route, if it matches the specified view, otherwise null.
17
+ */
18
+ export function useViewRoute(view) {
19
+ const route = useContext(RouteItemContext);
20
+ if (route.view === view) {
21
+ return route;
22
+ }
23
+ else {
24
+ return null;
25
+ }
26
+ }
@@ -0,0 +1,5 @@
1
+ import { RouteMeta } from "../types";
2
+ export declare const $routeMetaStore: {
3
+ data: RouteMeta;
4
+ };
5
+ export declare function useRouteMeta(): RouteMeta;
@@ -0,0 +1,9 @@
1
+ import { proxy, useSnapshot } from "valtio";
2
+ export const $routeMetaStore = proxy({
3
+ data: {},
4
+ });
5
+ export function useRouteMeta() {
6
+ return useSnapshot($routeMetaStore, {
7
+ sync: true,
8
+ }).data;
9
+ }