@void/react 0.7.4 → 0.7.5

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.
package/README.md CHANGED
@@ -36,6 +36,7 @@ Main runtime APIs live at `@void/react`:
36
36
 
37
37
  - `Link`
38
38
  - `useRouter()`
39
+ - `useParams()`
39
40
  - `useNavigation()`
40
41
  - `useShared()`
41
42
  - `useForm()`
@@ -142,6 +143,11 @@ accepts `{ data, method, params }`.
142
143
  `useRouter()` returns the Void Router. `visit()`, `refresh()`, and `prefetch()`
143
144
  are awaitable; `prefetch()` resolves when the page data has been cached.
144
145
 
146
+ ### `useParams`
147
+
148
+ `useParams()` returns dynamic route params for the page currently being rendered.
149
+ Use it instead of parsing `useRouter().path` in dynamic Pages routes.
150
+
145
151
  ### `Link`
146
152
 
147
153
  `Link` is the React Pages navigation component. GET links render an `<a>` and
@@ -3,7 +3,8 @@ import { idleNavigationState } from "void/pages-client";
3
3
  //#region src/runtime/context.ts
4
4
  const SharedContext = createContext(null);
5
5
  const ErrorsContext = createContext(null);
6
+ const ParamsContext = createContext(null);
6
7
  const RouterContext = createContext(null);
7
8
  const NavigationContext = createContext(idleNavigationState());
8
9
  //#endregion
9
- export { SharedContext as i, NavigationContext as n, RouterContext as r, ErrorsContext as t };
10
+ export { SharedContext as a, RouterContext as i, NavigationContext as n, ParamsContext as r, ErrorsContext as t };
@@ -48,6 +48,9 @@ declare function Link({
48
48
  //#region src/runtime/use-router.d.ts
49
49
  declare function useRouter(): VoidRouter;
50
50
  //#endregion
51
+ //#region src/runtime/use-params.d.ts
52
+ declare function useParams<T extends Record<string, string> = Record<string, string>>(): T;
53
+ //#endregion
51
54
  //#region src/runtime/use-shared.d.ts
52
55
  declare function useShared<T = CloudContextVariables["shared"]>(): T;
53
56
  //#endregion
@@ -116,10 +119,11 @@ declare function action<U extends ActionUrl & string>(url: U, ...args: HasParams
116
119
  //#region src/runtime/context.d.ts
117
120
  declare const SharedContext: Context<Record<string, unknown> | null>;
118
121
  declare const ErrorsContext: Context<Record<string, string> | null>;
122
+ declare const ParamsContext: Context<Record<string, string> | null>;
119
123
  declare const RouterContext: Context<VoidRouter | null>;
120
124
  declare const NavigationContext: Context<NavigationState>;
121
125
  //#endregion
122
126
  //#region src/runtime/index.d.ts
123
127
  type Deferred<T> = Promise<T>;
124
128
  //#endregion
125
- export { RouterContext as a, setActionRouter as c, useForm as d, useShared as f, NavigationContext as i, useIslandForm as l, Link as m, InferProps as n, SharedContext as o, useRouter as p, ErrorsContext as r, action as s, Deferred as t, useNavigation as u };
129
+ export { ParamsContext as a, action as c, useNavigation as d, useForm as f, Link as g, useRouter as h, NavigationContext as i, setActionRouter as l, useParams as m, InferProps as n, RouterContext as o, useShared as p, ErrorsContext as r, SharedContext as s, Deferred as t, useIslandForm as u };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as RouterContext, c as setActionRouter, d as useForm, f as useShared, i as NavigationContext, l as useIslandForm, m as Link, n as InferProps, o as SharedContext, p as useRouter, r as ErrorsContext, s as action, t as Deferred, u as useNavigation } from "./index-6hxGVqsE.mjs";
2
- export { Deferred, ErrorsContext, InferProps, Link, NavigationContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useRouter, useShared };
1
+ import { a as ParamsContext, c as action, d as useNavigation, f as useForm, g as Link, h as useRouter, i as NavigationContext, l as setActionRouter, m as useParams, n as InferProps, o as RouterContext, p as useShared, r as ErrorsContext, s as SharedContext, t as Deferred, u as useIslandForm } from "./index-75EO-lLe.mjs";
2
+ export { Deferred, ErrorsContext, InferProps, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as SharedContext, n as NavigationContext, r as RouterContext, t as ErrorsContext } from "./context-BCeFV8Jy.mjs";
2
- import { a as useRouter, i as useShared, n as useNavigation, o as Link, r as useForm, t as useIslandForm } from "./runtime-C24S_Dlg.mjs";
1
+ import { a as SharedContext, i as RouterContext, n as NavigationContext, r as ParamsContext, t as ErrorsContext } from "./context-CBGCQE3p.mjs";
2
+ import { a as useParams, i as useShared, n as useNavigation, o as useRouter, r as useForm, s as Link, t as useIslandForm } from "./runtime-BpEAl7K2.mjs";
3
3
  import { n as setActionRouter, t as action } from "./action-BFWtavbf.mjs";
4
- export { ErrorsContext, Link, NavigationContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useRouter, useShared };
4
+ export { ErrorsContext, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
package/dist/plugin.mjs CHANGED
@@ -324,7 +324,7 @@ function generateIslandRenderer(scan, pagesDir, isDev, islandCssMap, viteRoot, m
324
324
  return `
325
325
  import React from "react";
326
326
  import { renderToString } from "react-dom/server";
327
- import { SharedContext, ErrorsContext } from "@void/react";
327
+ import { SharedContext, ErrorsContext, ParamsContext } from "@void/react";
328
328
  import { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from "void/pages-head";
329
329
 
330
330
  ${generateComponentManifest(scan, pagesDir)}
@@ -355,9 +355,13 @@ export async function renderIslandPage(pageObj, assetTags) {
355
355
  SharedContext.Provider,
356
356
  { value: pageObj.shared || {} },
357
357
  React.createElement(
358
- ErrorsContext.Provider,
359
- { value: pageObj.errors || {} },
360
- element
358
+ ParamsContext.Provider,
359
+ { value: pageObj.params || {} },
360
+ React.createElement(
361
+ ErrorsContext.Provider,
362
+ { value: pageObj.errors || {} },
363
+ element
364
+ )
361
365
  )
362
366
  );
363
367
 
@@ -1,2 +1,2 @@
1
- import { a as RouterContext, c as setActionRouter, d as useForm, f as useShared, i as NavigationContext, l as useIslandForm, m as Link, n as InferProps, o as SharedContext, p as useRouter, r as ErrorsContext, s as action, t as Deferred, u as useNavigation } from "../index-6hxGVqsE.mjs";
2
- export { Deferred, ErrorsContext, InferProps, Link, NavigationContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useRouter, useShared };
1
+ import { a as ParamsContext, c as action, d as useNavigation, f as useForm, g as Link, h as useRouter, i as NavigationContext, l as setActionRouter, m as useParams, n as InferProps, o as RouterContext, p as useShared, r as ErrorsContext, s as SharedContext, t as Deferred, u as useIslandForm } from "../index-75EO-lLe.mjs";
2
+ export { Deferred, ErrorsContext, InferProps, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
@@ -1,4 +1,4 @@
1
- import { i as SharedContext, n as NavigationContext, r as RouterContext, t as ErrorsContext } from "../context-BCeFV8Jy.mjs";
2
- import { a as useRouter, i as useShared, n as useNavigation, o as Link, r as useForm, t as useIslandForm } from "../runtime-C24S_Dlg.mjs";
1
+ import { a as SharedContext, i as RouterContext, n as NavigationContext, r as ParamsContext, t as ErrorsContext } from "../context-CBGCQE3p.mjs";
2
+ import { a as useParams, i as useShared, n as useNavigation, o as useRouter, r as useForm, s as Link, t as useIslandForm } from "../runtime-BpEAl7K2.mjs";
3
3
  import { n as setActionRouter, t as action } from "../action-BFWtavbf.mjs";
4
- export { ErrorsContext, Link, NavigationContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useRouter, useShared };
4
+ export { ErrorsContext, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
@@ -1,4 +1,4 @@
1
- import { i as SharedContext, n as NavigationContext, r as RouterContext, t as ErrorsContext } from "../context-BCeFV8Jy.mjs";
1
+ import { a as SharedContext, i as RouterContext, n as NavigationContext, r as ParamsContext, t as ErrorsContext } from "../context-CBGCQE3p.mjs";
2
2
  import { n as setActionRouter } from "../action-BFWtavbf.mjs";
3
3
  import React, { Suspense, startTransition, use, useCallback, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useRef, useTransition } from "react";
4
4
  import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, isCallSiteActionError } from "void/pages-client";
@@ -8,6 +8,7 @@ const deferredState = /* @__PURE__ */ new WeakMap();
8
8
  const viewTransitionWaiters = /* @__PURE__ */ new Map();
9
9
  const pendingVisitSettlers = /* @__PURE__ */ new Map();
10
10
  const committedResources = /* @__PURE__ */ new Set();
11
+ const EMPTY_PARAMS = {};
11
12
  let activePendingNavigationId = null;
12
13
  let scheduleVisit = null;
13
14
  function createDeferredResource() {
@@ -116,6 +117,9 @@ function createRouter(engine) {
116
117
  get query() {
117
118
  return this.url.searchParams;
118
119
  },
120
+ get params() {
121
+ return {};
122
+ },
119
123
  visit(url, options = {}) {
120
124
  if (!scheduleVisit) return Promise.reject(/* @__PURE__ */ new Error("router.visit() called before router initialized"));
121
125
  return scheduleVisit(normalizeUrl(url), options);
@@ -141,6 +145,7 @@ function createRouter(engine) {
141
145
  }
142
146
  function RouteResource({ resource, onCommit }) {
143
147
  const result = use(resource.shell);
148
+ const outerRouter = React.useContext(RouterContext);
144
149
  useLayoutEffect(() => {
145
150
  if (result) onCommit(resource, result);
146
151
  }, [
@@ -151,12 +156,23 @@ function RouteResource({ resource, onCommit }) {
151
156
  if (!result) return null;
152
157
  const pageData = result.pageData;
153
158
  const PageComponent = result.component;
159
+ const routeParams = pageData.params ?? EMPTY_PARAMS;
160
+ const routeRouter = useMemo(() => createRouterFacade(outerRouter, () => {
161
+ const outerUrl = outerRouter.url;
162
+ const outerPath = outerUrl.pathname + outerUrl.search;
163
+ return outerPath === pageData.url ? outerPath + outerUrl.hash : pageData.url + resource.hash;
164
+ }, () => routeParams), [
165
+ outerRouter,
166
+ pageData.url,
167
+ resource.hash,
168
+ routeParams
169
+ ]);
154
170
  let element = React.createElement(PageComponent, pageData.props);
155
171
  for (let i = result.layouts.length - 1; i >= 0; i--) {
156
172
  const Layout = result.layouts[i];
157
173
  element = React.createElement(Layout, null, element);
158
174
  }
159
- return React.createElement(SharedContext.Provider, { value: pageData.shared }, React.createElement(ErrorsContext.Provider, { value: pageData.errors ?? {} }, element));
175
+ return React.createElement(RouterContext.Provider, { value: routeRouter }, React.createElement(ParamsContext.Provider, { value: routeParams }, React.createElement(SharedContext.Provider, { value: pageData.shared }, React.createElement(ErrorsContext.Provider, { value: pageData.errors ?? {} }, element))));
160
176
  }
161
177
  function startViewTransition(resource, reveal, enabled) {
162
178
  if (!enabled || typeof document.startViewTransition !== "function") {
@@ -1,4 +1,4 @@
1
- import { i as SharedContext, n as NavigationContext, r as RouterContext, t as ErrorsContext } from "../context-BCeFV8Jy.mjs";
1
+ import { a as SharedContext, i as RouterContext, n as NavigationContext, r as ParamsContext, t as ErrorsContext } from "../context-CBGCQE3p.mjs";
2
2
  import React from "react";
3
3
  import { createSsrRouter, idleNavigationState } from "void/pages-client";
4
4
  import { renderToReadableStream } from "react-dom/server";
@@ -84,7 +84,7 @@ async function renderReactPage({ pageObj, assetTags, components, layoutTree, pre
84
84
  const renderProps = propsForReactRender(pageObj);
85
85
  let element = React.createElement(PageComponent, renderProps);
86
86
  for (let i = layoutComponents.length - 1; i >= 0; i--) element = React.createElement(layoutComponents[i], null, element);
87
- element = React.createElement(RouterContext.Provider, { value: createSsrRouter(pageObj.url || "/") }, React.createElement(NavigationContext.Provider, { value: idleNavigationState() }, React.createElement(React.Suspense, { fallback: null }, React.createElement(SharedContext.Provider, { value: pageObj.shared || {} }, React.createElement(ErrorsContext.Provider, { value: pageObj.errors || {} }, element)))));
87
+ element = React.createElement(RouterContext.Provider, { value: createSsrRouter(pageObj.url || "/", pageObj.params ?? {}) }, React.createElement(NavigationContext.Provider, { value: idleNavigationState() }, React.createElement(React.Suspense, { fallback: null }, React.createElement(SharedContext.Provider, { value: pageObj.shared || {} }, React.createElement(ParamsContext.Provider, { value: pageObj.params ?? {} }, React.createElement(ErrorsContext.Provider, { value: pageObj.errors || {} }, element))))));
88
88
  const appStream = await renderToReadableStream(pageObj.deferredKeys ? React.createElement(React.Fragment, null, element, React.createElement("template", { id: DEFERRED_SHELL_END_ID })) : element, { onError(error) {
89
89
  if (error === DEFERRED_SHELL_CANCEL_REASON) return;
90
90
  throw error;
@@ -1,4 +1,4 @@
1
- import { i as SharedContext, n as NavigationContext, r as RouterContext } from "./context-BCeFV8Jy.mjs";
1
+ import { a as SharedContext, i as RouterContext, n as NavigationContext, r as ParamsContext } from "./context-CBGCQE3p.mjs";
2
2
  import "./action-BFWtavbf.mjs";
3
3
  import { useActionState, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { VoidActionError, categorizeActionError, isAbortError, isEqualFormValue, ssrProxy, submitAction } from "void/pages-client";
@@ -232,6 +232,13 @@ function useRouter() {
232
232
  return useContext(RouterContext) ?? ssrProxy;
233
233
  }
234
234
  //#endregion
235
+ //#region src/runtime/use-params.ts
236
+ function useParams() {
237
+ const params = useContext(ParamsContext);
238
+ if (params === null) throw new Error("useParams(): must be used inside a Void page.");
239
+ return params;
240
+ }
241
+ //#endregion
235
242
  //#region src/runtime/use-shared.ts
236
243
  function useShared() {
237
244
  const shared = useContext(SharedContext);
@@ -489,4 +496,4 @@ function useIslandForm(defaults) {
489
496
  };
490
497
  }
491
498
  //#endregion
492
- export { useRouter as a, useShared as i, useNavigation as n, Link as o, useForm as r, useIslandForm as t };
499
+ export { useParams as a, useShared as i, useNavigation as n, useRouter as o, useForm as r, Link as s, useIslandForm as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/react",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -51,13 +51,13 @@
51
51
  "react-dom": "^19.2.6",
52
52
  "vite": "npm:@voidzero-dev/vite-plus-core@0.1.20",
53
53
  "vite-plus": "^0.1.20",
54
- "void": "0.7.4"
54
+ "void": "0.7.5"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "react": "^19.0.0",
58
58
  "react-dom": "^19.0.0",
59
59
  "vite": "npm:@voidzero-dev/vite-plus-core@0.1.20",
60
- "void": "0.7.4"
60
+ "void": "0.7.5"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "vp pack",