@nifrajs/web-react 2.2.0 → 2.4.0

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 (52) hide show
  1. package/README.md +3 -3
  2. package/dist/await.d.ts +2 -2
  3. package/dist/await.js +2 -2
  4. package/dist/client.d.ts +2 -2
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +13 -6
  7. package/dist/client.js.map +1 -1
  8. package/dist/compose.d.ts +4 -3
  9. package/dist/compose.d.ts.map +1 -1
  10. package/dist/compose.js +8 -4
  11. package/dist/compose.js.map +1 -1
  12. package/dist/content.d.ts +2 -2
  13. package/dist/content.js +2 -2
  14. package/dist/error.d.ts +1 -1
  15. package/dist/error.js +3 -3
  16. package/dist/fetcher.d.ts +2 -2
  17. package/dist/fetcher.js +4 -4
  18. package/dist/fn.d.ts +29 -0
  19. package/dist/fn.d.ts.map +1 -0
  20. package/dist/fn.js +31 -0
  21. package/dist/fn.js.map +1 -0
  22. package/dist/i18n.d.ts +1 -1
  23. package/dist/i18n.js +1 -1
  24. package/dist/image.d.ts +3 -3
  25. package/dist/image.js +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +7 -7
  28. package/dist/island.d.ts +3 -3
  29. package/dist/island.js +2 -2
  30. package/dist/query.d.ts +8 -8
  31. package/dist/query.js +5 -5
  32. package/dist/react-dom-server.d.ts +7 -7
  33. package/dist/react-dom-server.js +7 -7
  34. package/dist/router.d.ts +66 -18
  35. package/dist/router.d.ts.map +1 -1
  36. package/dist/router.js +80 -15
  37. package/dist/router.js.map +1 -1
  38. package/package.json +11 -6
  39. package/src/await.ts +2 -2
  40. package/src/client.ts +13 -7
  41. package/src/compose.ts +9 -4
  42. package/src/content.ts +2 -2
  43. package/src/error.ts +3 -3
  44. package/src/fetcher.ts +4 -4
  45. package/src/fn.ts +43 -0
  46. package/src/i18n.ts +1 -1
  47. package/src/image.ts +3 -3
  48. package/src/index.ts +7 -7
  49. package/src/island.ts +3 -3
  50. package/src/query.ts +9 -9
  51. package/src/react-dom-server.ts +9 -9
  52. package/src/router.ts +114 -24
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @nifrajs/web-react
2
2
 
3
- React render adapter for @nifrajs/web — SSR + hydration (Bun-native JSX, no Babel).
3
+ React render adapter for @nifrajs/web - SSR + hydration (Bun-native JSX, no Babel).
4
4
 
5
- Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework — one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
5
+ Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
6
6
 
7
7
  ## Install
8
8
 
@@ -19,7 +19,7 @@ MIT
19
19
 
20
20
  ## For AI agents
21
21
 
22
- Start with [`LLM.md`](./LLM.md) — this package's contract card (the exports you call + its footguns),
22
+ Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
23
23
  one cheap read instead of the whole corpus. For the wider framework: the repo's
24
24
  [`AGENTS.md`](../../AGENTS.md) is the copy-paste quick reference, and
25
25
  [`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
package/dist/await.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Deferred } from "@nifrajs/web";
2
2
  /**
3
- * `@nifrajs/web-react/await` — the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
3
+ * `@nifrajs/web-react/await` - the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
4
4
  * and imports only `react` + a type from `@nifrajs/web` (never `react-dom/server`), so route components
5
5
  * can use it without dragging server code into the client bundle. No JSX (the package builds with
6
6
  * plain `tsc`).
@@ -8,7 +8,7 @@ import type { Deferred } from "@nifrajs/web";
8
8
  * The server streams the boundary: `use(promise)` suspends, React flushes the fallback then the
9
9
  * resolved content mid-stream. On the client the registry promise is already settled (the core's
10
10
  * streamed `__nifraResolve` script tagged it `fulfilled`), so `use()` returns the value synchronously
11
- * — React hydrates the server-revealed boundary's content directly (no re-fetch, no fallback flash).
11
+ * - React hydrates the server-revealed boundary's content directly (no re-fetch, no fallback flash).
12
12
  */
13
13
  import { type ReactNode } from "react";
14
14
  export interface AwaitProps<T> {
package/dist/await.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/await` — the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
2
+ * `@nifrajs/web-react/await` - the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
3
3
  * and imports only `react` + a type from `@nifrajs/web` (never `react-dom/server`), so route components
4
4
  * can use it without dragging server code into the client bundle. No JSX (the package builds with
5
5
  * plain `tsc`).
@@ -7,7 +7,7 @@
7
7
  * The server streams the boundary: `use(promise)` suspends, React flushes the fallback then the
8
8
  * resolved content mid-stream. On the client the registry promise is already settled (the core's
9
9
  * streamed `__nifraResolve` script tagged it `fulfilled`), so `use()` returns the value synchronously
10
- * — React hydrates the server-revealed boundary's content directly (no re-fetch, no fallback flash).
10
+ * - React hydrates the server-revealed boundary's content directly (no re-fetch, no fallback flash).
11
11
  */
12
12
  import { Component, createElement, Suspense, use } from "react";
13
13
  // Catches the rejection `use()` throws when the deferred rejects → renders `errorFallback`. A class
package/dist/client.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import type { MountRouterOptions, RenderProps } from "@nifrajs/web";
1
+ import { type MountRouterOptions, type RenderProps } from "@nifrajs/web";
2
2
  export { errorBoundary } from "./error.js";
3
3
  /** Hydrate a server-rendered React layout `chain` (with the loader `props`) inside `container`. */
4
4
  export declare function hydrate(chain: readonly unknown[], props: RenderProps, container: unknown): void;
5
5
  /**
6
6
  * Hydrate a stateful React Router. `useSyncExternalStore` subscribes to the agnostic store and
7
- * re-renders the matched layout chain on each store change — so client navigations swap routes
7
+ * re-renders the matched layout chain on each store change - so client navigations swap routes
8
8
  * without a full reload. `getServerSnapshot` (3rd arg) returns the initial state, matching the
9
9
  * SSR markup on hydration.
10
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAcnE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAE/F;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAmB7D"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAiB,MAAM,cAAc,CAAA;AAcvF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAE/F;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAyB7D"}
package/dist/client.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { searchOfChain } from "@nifrajs/web";
1
2
  /**
2
- * @nifrajs/web-react/client — React client runtime. `hydrate` hydrates a single SSR'd route;
3
+ * @nifrajs/web-react/client - React client runtime. `hydrate` hydrates a single SSR'd route;
3
4
  * `mountRouter` hydrates a stateful Router that subscribes to the agnostic store (via
4
5
  * `useSyncExternalStore`) and re-renders the matched chain on every client navigation (no full
5
6
  * reload). Kept in its own entry so server code stays out of the client bundle.
@@ -8,7 +9,7 @@ import { createElement, useSyncExternalStore } from "react";
8
9
  import { hydrateRoot } from "react-dom/client";
9
10
  import { compose } from "./compose.js";
10
11
  import { setMountedRouter } from "./fetcher.js";
11
- // The `_error` boundary chain element — defined in its own (react-dom-free) module, re-exported here so
12
+ // The `_error` boundary chain element - defined in its own (react-dom-free) module, re-exported here so
12
13
  // nifra's client codegen resolves it from `@nifrajs/web-react/client` alongside `mountRouter`.
13
14
  export { errorBoundary } from "./error.js";
14
15
  /** Hydrate a server-rendered React layout `chain` (with the loader `props`) inside `container`. */
@@ -17,25 +18,31 @@ export function hydrate(chain, props, container) {
17
18
  }
18
19
  /**
19
20
  * Hydrate a stateful React Router. `useSyncExternalStore` subscribes to the agnostic store and
20
- * re-renders the matched layout chain on each store change — so client navigations swap routes
21
+ * re-renders the matched layout chain on each store change - so client navigations swap routes
21
22
  * without a full reload. `getServerSnapshot` (3rd arg) returns the initial state, matching the
22
23
  * SSR markup on hydration.
23
24
  */
24
25
  export function mountRouter(options) {
25
- const { router, routes, container } = options;
26
+ const { router, routes, searchSchemas, container } = options;
26
27
  setMountedRouter(router); // expose it to useFetcher/useFetchers (same page, client-only)
27
28
  const Router = () => {
28
29
  const state = useSyncExternalStore(router.subscribe, router.snapshot, router.snapshot);
30
+ // Derive this route's typed `search` from the URL query + the route's schema CHAIN (layout schemas +
31
+ // page, merged page-wins), the SAME `searchOfChain` the server ran, so `useSearch` reads an identical
32
+ // value and hydrates with no drift.
33
+ const q = state.path.indexOf("?");
34
+ const rawSearch = q === -1 ? "" : state.path.slice(q);
29
35
  return compose(routes[state.routeId] ?? [], {
30
36
  data: state.data,
31
37
  actionData: state.actionData,
32
38
  pending: state.pending,
33
39
  ...(state.pendingPath !== undefined ? { pendingPath: state.pendingPath } : {}),
34
- // `params`/`path` feed the routing hooks (useParams/useLocation) via compose's RouterContext —
40
+ // `params`/`path` feed the routing hooks (useParams/useLocation) via compose's RouterContext -
35
41
  // sourced from router state here, matching the SSR render's request-derived values on hydration.
36
42
  params: state.params,
37
43
  path: state.path,
38
- // The in-flight submission (for optimistic UI) — spread only when present.
44
+ search: searchOfChain(searchSchemas?.[state.routeId] ?? [], rawSearch),
45
+ // The in-flight submission (for optimistic UI) - spread only when present.
39
46
  ...(state.submission ? { submission: state.submission } : {}),
40
47
  });
41
48
  };
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAA0B,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,wGAAwG;AACxG,+FAA+F;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,WAAW,CAAC,SAAoB,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAC7C,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,+DAA+D;IACxF,MAAM,MAAM,GAAsB,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACtF,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE;YAC1C,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9E,+FAA+F;YAC/F,iGAAiG;YACjG,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,2EAA2E;YAC3E,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAA;IACJ,CAAC,CAAA;IACD,WAAW,CAAC,SAAoB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;AAC1D,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,aAAa,EAAE,MAAM,cAAc,CAAA;AACvF;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAA0B,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,wGAAwG;AACxG,+FAA+F;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,WAAW,CAAC,SAAoB,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAC5D,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,+DAA+D;IACxF,MAAM,MAAM,GAAsB,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACtF,qGAAqG;QACrG,sGAAsG;QACtG,oCAAoC;QACpC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACrD,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE;YAC1C,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9E,+FAA+F;YAC/F,iGAAiG;YACjG,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,aAAa,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC;YACtE,2EAA2E;YAC3E,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAA;IACJ,CAAC,CAAA;IACD,WAAW,CAAC,SAAoB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;AAC1D,CAAC"}
package/dist/compose.d.ts CHANGED
@@ -6,9 +6,10 @@ import { type ReactNode } from "react";
6
6
  * `children`. Shared by the server adapter (renderToString) and the client (hydrateRoot).
7
7
  *
8
8
  * The whole tree is wrapped in a {@link RouterContext} provider carrying the matched `params`, the
9
- * current `path`, and the client `pending` flag (all threaded through `RenderProps` identically on SSR
10
- * and client), so the routing hooks (`useParams`/`useLocation`/`useNavigation`) read the same value on
11
- * both sides - no hydration mismatch (`pending` is `false` on SSR and on the initial client render).
9
+ * current `path`, the validated `search`, and the client `pending` flag (all threaded through
10
+ * `RenderProps` identically on SSR and client), so the routing hooks
11
+ * (`useParams`/`useLocation`/`useSearch`/`useNavigation`) read the same value on both sides - no
12
+ * hydration mismatch (`pending` is `false` on SSR and on the initial client render).
12
13
  * A render with no routing fields (a non-router adapter usage) provides the empty default.
13
14
  */
14
15
  export declare function compose(chain: readonly unknown[], props: RenderProps): ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAyC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAM7E;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,CA0BhF"}
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAyC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAS7E;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,CA2BhF"}
package/dist/compose.js CHANGED
@@ -2,22 +2,25 @@ import { createElement } from "react";
2
2
  import { RouterContext } from "./router.js";
3
3
  // Stable empty params so the provider value's `params` has a fixed reference when a route has none.
4
4
  const EMPTY_PARAMS = Object.freeze({});
5
+ // Stable empty search for the same reason: a render with no search context (or a non-router usage).
6
+ const EMPTY_SEARCH = Object.freeze({});
5
7
  /**
6
8
  * Fold a layout chain (outermost layout → page) into a single React tree: the page
7
9
  * (innermost) receives `props` (the loader data); each layout wraps the child via its
8
10
  * `children`. Shared by the server adapter (renderToString) and the client (hydrateRoot).
9
11
  *
10
12
  * The whole tree is wrapped in a {@link RouterContext} provider carrying the matched `params`, the
11
- * current `path`, and the client `pending` flag (all threaded through `RenderProps` identically on SSR
12
- * and client), so the routing hooks (`useParams`/`useLocation`/`useNavigation`) read the same value on
13
- * both sides - no hydration mismatch (`pending` is `false` on SSR and on the initial client render).
13
+ * current `path`, the validated `search`, and the client `pending` flag (all threaded through
14
+ * `RenderProps` identically on SSR and client), so the routing hooks
15
+ * (`useParams`/`useLocation`/`useSearch`/`useNavigation`) read the same value on both sides - no
16
+ * hydration mismatch (`pending` is `false` on SSR and on the initial client render).
14
17
  * A render with no routing fields (a non-router adapter usage) provides the empty default.
15
18
  */
16
19
  export function compose(chain, props) {
17
20
  const last = chain.length - 1;
18
21
  let node = createElement(chain[last], props);
19
22
  for (let i = last - 1; i >= 0; i--) {
20
- // children passed as the 3rd arg (not a `children` prop) — React's canonical form.
23
+ // children passed as the 3rd arg (not a `children` prop) - React's canonical form.
21
24
  // Each layout receives its own loader data at its own index. Layouts are the chain's leading
22
25
  // prefix, so `layoutData[i]` belongs to `chain[i]`; anything past that end (a client-only `_error`
23
26
  // boundary marker, the page) reads `undefined` and is unaffected.
@@ -27,6 +30,7 @@ export function compose(chain, props) {
27
30
  value: {
28
31
  params: props.params ?? EMPTY_PARAMS,
29
32
  path: props.path ?? "",
33
+ search: props.search ?? EMPTY_SEARCH,
30
34
  pending: props.pending ?? false,
31
35
  pendingPath: props.pendingPath,
32
36
  },
@@ -1 +1 @@
1
- {"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA0C,MAAM,OAAO,CAAA;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,oGAAoG;AACpG,MAAM,YAAY,GAAqC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAExE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB;IACnE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7B,IAAI,IAAI,GAAc,aAAa,CAAC,KAAK,CAAC,IAAI,CAAmC,EAAE,KAAK,CAAC,CAAA;IACzF,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,mFAAmF;QACnF,6FAA6F;QAC7F,mGAAmG;QACnG,kEAAkE;QAClE,IAAI,GAAG,aAAa,CAClB,KAAK,CAAC,CAAC,CAAyC,EAChD,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EACvC,IAAI,CACL,CAAA;IACH,CAAC;IACD,OAAO,aAAa,CAClB,aAAa,CAAC,QAAQ,EACtB;QACE,KAAK,EAAE;YACL,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,YAAY;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK;YAC/B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B;KACF,EACD,IAAI,CACL,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA0C,MAAM,OAAO,CAAA;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,oGAAoG;AACpG,MAAM,YAAY,GAAqC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAExE,oGAAoG;AACpG,MAAM,YAAY,GAAsC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAEzE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB;IACnE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7B,IAAI,IAAI,GAAc,aAAa,CAAC,KAAK,CAAC,IAAI,CAAmC,EAAE,KAAK,CAAC,CAAA;IACzF,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,mFAAmF;QACnF,6FAA6F;QAC7F,mGAAmG;QACnG,kEAAkE;QAClE,IAAI,GAAG,aAAa,CAClB,KAAK,CAAC,CAAC,CAAyC,EAChD,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EACvC,IAAI,CACL,CAAA;IACH,CAAC;IACD,OAAO,aAAa,CAClB,aAAa,CAAC,QAAQ,EACtB;QACE,KAAK,EAAE;YACL,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,YAAY;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,YAAY;YACpC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK;YAC/B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B;KACF,EACD,IAAI,CACL,CAAA;AACH,CAAC"}
package/dist/content.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `@nifrajs/web-react/content` — render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
2
+ * `@nifrajs/web-react/content` - render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
3
3
  * `.html`, or any Markdown→HTML string) into the DOM via `dangerouslySetInnerHTML`. Pairs with content
4
4
  * collections: `<Content html={entry.html} />`.
5
5
  *
6
6
  * Security: this injects raw HTML, so the `html` MUST be trusted (your own Markdown/content, rendered
7
- * at build/server time) — never pass user-supplied HTML without sanitizing it first.
7
+ * at build/server time) - never pass user-supplied HTML without sanitizing it first.
8
8
  */
9
9
  import { type ComponentPropsWithoutRef, type ElementType, type ReactElement } from "react";
10
10
  export interface ContentProps extends Omit<ComponentPropsWithoutRef<"div">, "dangerouslySetInnerHTML" | "children"> {
package/dist/content.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `@nifrajs/web-react/content` — render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
2
+ * `@nifrajs/web-react/content` - render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
3
3
  * `.html`, or any Markdown→HTML string) into the DOM via `dangerouslySetInnerHTML`. Pairs with content
4
4
  * collections: `<Content html={entry.html} />`.
5
5
  *
6
6
  * Security: this injects raw HTML, so the `html` MUST be trusted (your own Markdown/content, rendered
7
- * at build/server time) — never pass user-supplied HTML without sanitizing it first.
7
+ * at build/server time) - never pass user-supplied HTML without sanitizing it first.
8
8
  */
9
9
  import { createElement, } from "react";
10
10
  /** Render trusted HTML into a wrapper element. Extra props (`className`, `id`, `style`, …) pass through. */
package/dist/error.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Build an error-boundary chain element bound to `fallback` (a route's `_error` component). nifra's
3
3
  * client codegen inserts it before the page in the matched chain; a render error in the subtree renders
4
4
  * `fallback` with `{ data: { name, message } }` instead of crashing the app. DOM-transparent (it renders
5
- * its children directly — no wrapper element), so it adds no markup and never disturbs hydration.
5
+ * its children directly - no wrapper element), so it adds no markup and never disturbs hydration.
6
6
  */
7
7
  export declare function errorBoundary(fallback: unknown): unknown;
8
8
  //# sourceMappingURL=error.d.ts.map
package/dist/error.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `errorBoundary` — the React error-boundary chain element for nifra's `_error.tsx`. Kept in its own
2
+ * `errorBoundary` - the React error-boundary chain element for nifra's `_error.tsx`. Kept in its own
3
3
  * module (imports only `react`, never `react-dom/client`) so it's unit-testable off the DOM and the
4
4
  * client codegen can import it from `@nifrajs/web-react/client` (which re-exports it).
5
5
  */
@@ -8,7 +8,7 @@ import { Component, createElement } from "react";
8
8
  * Build an error-boundary chain element bound to `fallback` (a route's `_error` component). nifra's
9
9
  * client codegen inserts it before the page in the matched chain; a render error in the subtree renders
10
10
  * `fallback` with `{ data: { name, message } }` instead of crashing the app. DOM-transparent (it renders
11
- * its children directly — no wrapper element), so it adds no markup and never disturbs hydration.
11
+ * its children directly - no wrapper element), so it adds no markup and never disturbs hydration.
12
12
  */
13
13
  export function errorBoundary(fallback) {
14
14
  return class NifraErrorBoundary extends Component {
@@ -23,7 +23,7 @@ export function errorBoundary(fallback) {
23
23
  const { error } = this.state;
24
24
  if (error === null)
25
25
  return this.props.children;
26
- // `fallback` is the route's `_error` default export — opaque to the core, a component here.
26
+ // `fallback` is the route's `_error` default export - opaque to the core, a component here.
27
27
  const Fallback = fallback;
28
28
  return createElement(Fallback, { data: { name: error.name, message: error.message } });
29
29
  }
package/dist/fetcher.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ClientRouter, Fetcher, FetcherState } from "@nifrajs/web";
2
- /** Register (or clear) the router that owns fetchers — called by `mountRouter`. Not for app use. */
2
+ /** Register (or clear) the router that owns fetchers - called by `mountRouter`. Not for app use. */
3
3
  export declare function setMountedRouter(router: ClientRouter | undefined): void;
4
4
  /** A fetcher's reactive {@link FetcherState} plus its imperative `load`/`submit`. */
5
5
  export interface FetcherHandle extends FetcherState {
@@ -15,7 +15,7 @@ export interface FetcherHandle extends FetcherState {
15
15
  */
16
16
  export declare function useFetcher(key: string): FetcherHandle;
17
17
  /**
18
- * Subscribe to the whole live fetcher collection — for a global busy view (e.g. "3 saving…"). Read
18
+ * Subscribe to the whole live fetcher collection - for a global busy view (e.g. "3 saving…"). Read
19
19
  * each entry's `.snapshot()` for its state. Re-renders whenever any fetcher transitions or a new one
20
20
  * is created.
21
21
  */
package/dist/fetcher.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * `@nifrajs/web-react/fetcher` — React bindings for concurrent fetchers. `useFetcher(key)` subscribes a
2
+ * `@nifrajs/web-react/fetcher` - React bindings for concurrent fetchers. `useFetcher(key)` subscribes a
3
3
  * component to an independent {@link Fetcher} (via `useSyncExternalStore`) and returns its reactive
4
4
  * state plus `load`/`submit`; `useFetchers()` subscribes to the whole live collection. Imports only
5
5
  * `react` (never `react-dom/*`), so route components can use it on the server *and* client without
6
6
  * dragging either DOM build into the wrong bundle. No JSX (the package builds with plain `tsc`).
7
7
  *
8
- * The router that owns the fetchers is the one `mountRouter` hydrated — it registers itself here via
8
+ * The router that owns the fetchers is the one `mountRouter` hydrated - it registers itself here via
9
9
  * `setMountedRouter`. On the server (no mount) there is no router, so the hooks return an idle state
10
10
  * (fetchers are client-only); the first client render after `mountRouter` sees the real fetcher, so
11
11
  * there's no hydration mismatch.
@@ -14,7 +14,7 @@ import { useSyncExternalStore } from "react";
14
14
  // The active client router (set by `mountRouter`). Module-scoped: the browser mounts one app per
15
15
  // page, and fetchers never exist on the server. Shared with `client.ts`'s `mountRouter`.
16
16
  let mountedRouter;
17
- /** Register (or clear) the router that owns fetchers — called by `mountRouter`. Not for app use. */
17
+ /** Register (or clear) the router that owns fetchers - called by `mountRouter`. Not for app use. */
18
18
  export function setMountedRouter(router) {
19
19
  mountedRouter = router;
20
20
  }
@@ -35,7 +35,7 @@ export function useFetcher(key) {
35
35
  return { ...state, load: fetcher?.load ?? noopAsync, submit: fetcher?.submit ?? noopAsync };
36
36
  }
37
37
  /**
38
- * Subscribe to the whole live fetcher collection — for a global busy view (e.g. "3 saving…"). Read
38
+ * Subscribe to the whole live fetcher collection - for a global busy view (e.g. "3 saving…"). Read
39
39
  * each entry's `.snapshot()` for its state. Re-renders whenever any fetcher transitions or a new one
40
40
  * is created.
41
41
  */
package/dist/fn.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `@nifrajs/web-react/fn` - React binding for a server function's pending/error state.
3
+ *
4
+ * Calling a server function needs no hook: the client stub is `(input) => Promise<Output>`. This adds
5
+ * the part a component usually wants around it - in flight, last result, last error - and nothing more.
6
+ *
7
+ * The state machine is `@nifrajs/web`'s `createServerFnStore`, shared with every other adapter, so
8
+ * "is it pending" has one answer rather than five that drift. This file contributes only the `useSyncExternalStore` subscription.
9
+ */
10
+ import type { ServerFnReference } from "@nifrajs/web/fn";
11
+ import { type ServerFnState } from "@nifrajs/web/fn-state";
12
+ /** A server function's state plus the call itself. */
13
+ export interface ServerFnHandle<Input, Output> extends ServerFnState<Output> {
14
+ /** Invoke it. Records state, and rejects on failure - attach `.catch` if you only render state. */
15
+ readonly call: (input: Input) => Promise<Output>;
16
+ /** Back to idle. */
17
+ readonly reset: () => void;
18
+ }
19
+ /**
20
+ * Track one server function's call state.
21
+ *
22
+ * const addTodo = useServerFn(fns.addTodo)
23
+ * <button disabled={addTodo.pending} onClick={() => addTodo.call({ text }).catch(() => {})}>
24
+ *
25
+ * The store is per component instance and created once; `fn` is read on the first render only, so a
26
+ * freshly-created inline function neither resets the state nor goes stale.
27
+ */
28
+ export declare function useServerFn<Input, Output>(fn: ServerFnReference<Input, Output>): ServerFnHandle<Input, Output>;
29
+ //# sourceMappingURL=fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fn.d.ts","sourceRoot":"","sources":["../src/fn.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAG/E,sDAAsD;AACtD,MAAM,WAAW,cAAc,CAAC,KAAK,EAAE,MAAM,CAAE,SAAQ,aAAa,CAAC,MAAM,CAAC;IAC1E,mGAAmG;IACnG,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAChD,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EACvC,EAAE,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,GACnC,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAS/B"}
package/dist/fn.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `@nifrajs/web-react/fn` - React binding for a server function's pending/error state.
3
+ *
4
+ * Calling a server function needs no hook: the client stub is `(input) => Promise<Output>`. This adds
5
+ * the part a component usually wants around it - in flight, last result, last error - and nothing more.
6
+ *
7
+ * The state machine is `@nifrajs/web`'s `createServerFnStore`, shared with every other adapter, so
8
+ * "is it pending" has one answer rather than five that drift. This file contributes only the `useSyncExternalStore` subscription.
9
+ */
10
+ import { createServerFnStore } from "@nifrajs/web/fn-state";
11
+ import { useMemo, useRef, useSyncExternalStore } from "react";
12
+ /**
13
+ * Track one server function's call state.
14
+ *
15
+ * const addTodo = useServerFn(fns.addTodo)
16
+ * <button disabled={addTodo.pending} onClick={() => addTodo.call({ text }).catch(() => {})}>
17
+ *
18
+ * The store is per component instance and created once; `fn` is read on the first render only, so a
19
+ * freshly-created inline function neither resets the state nor goes stale.
20
+ */
21
+ export function useServerFn(fn) {
22
+ // The store is created once, but always calls the CURRENT `fn`. Capturing `fn` directly would
23
+ // either recreate the store on every render (losing the state) or hold the first render's closure
24
+ // (calling a stale one); the ref is what makes "created once" and "never stale" both true.
25
+ const latest = useRef(fn);
26
+ latest.current = fn;
27
+ const store = useMemo(() => createServerFnStore((input) => latest.current(input)), []);
28
+ const state = useSyncExternalStore(store.subscribe, store.snapshot, store.snapshot);
29
+ return { ...state, call: store.call, reset: store.reset };
30
+ }
31
+ //# sourceMappingURL=fn.js.map
package/dist/fn.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fn.js","sourceRoot":"","sources":["../src/fn.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,mBAAmB,EAAsB,MAAM,uBAAuB,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAU7D;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CACzB,EAAoC;IAEpC,8FAA8F;IAC9F,kGAAkG;IAClG,2FAA2F;IAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,EAAmC,CAAC,CAAA;IAC1D,MAAM,CAAC,OAAO,GAAG,EAAmC,CAAA;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAC,KAAY,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC7F,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IACnF,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAA;AAC3D,CAAC"}
package/dist/i18n.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/i18n` — React bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
2
+ * `@nifrajs/web-react/i18n` - React bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
3
3
  * `Formatter` (memoized) and provides it; `useT()` reads it. Both `locale` + `messages` are
4
4
  * serializable, so a loader returns them, the page renders with the negotiated catalog on the server,
5
5
  * and the client rebuilds the same formatter from the same props (no mismatch). Imports only `react` +
package/dist/i18n.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/i18n` — React bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
2
+ * `@nifrajs/web-react/i18n` - React bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
3
3
  * `Formatter` (memoized) and provides it; `useT()` reads it. Both `locale` + `messages` are
4
4
  * serializable, so a loader returns them, the page renders with the negotiated catalog on the server,
5
5
  * and the client rebuilds the same formatter from the same props (no mismatch). Imports only `react` +
package/dist/image.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/image` — a CLS-safe responsive React `<Image>`. A thin wrapper over
2
+ * `@nifrajs/web-react/image` - a CLS-safe responsive React `<Image>`. A thin wrapper over
3
3
  * `resolveImage` from `@nifrajs/image`: it computes `src`/`srcSet`/`sizes`/`width`/`height`/`loading`/
4
4
  * `decoding`/`fetchpriority` and renders a plain `<img>`, forwarding any extra DOM props
5
5
  * (`className`, `style`, `id`, event handlers, `data-*`, …). Resizing is delegated to the `loader`
@@ -7,10 +7,10 @@
7
7
  */
8
8
  import { type ImageLoader, type ImageProps } from "@nifrajs/image";
9
9
  import { type ComponentPropsWithoutRef, type ReactElement } from "react";
10
- /** Attributes `resolveImage` computes — callers can't override them via DOM passthrough. */
10
+ /** Attributes `resolveImage` computes - callers can't override them via DOM passthrough. */
11
11
  type ComputedAttrs = "src" | "srcSet" | "sizes" | "width" | "height" | "alt" | "loading" | "decoding" | "fetchPriority";
12
12
  export interface ImageComponentProps extends ImageProps, Omit<ComponentPropsWithoutRef<"img">, ComputedAttrs | keyof ImageProps> {
13
- /** CDN URL builder. Defaults to the identity loader (no transform — still CLS-safe + lazy). */
13
+ /** CDN URL builder. Defaults to the identity loader (no transform - still CLS-safe + lazy). */
14
14
  readonly loader?: ImageLoader;
15
15
  /** `data-*` attributes pass through to the `<img>` (React doesn't auto-allow these on a custom
16
16
  * component, so they're declared explicitly). */
package/dist/image.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/image` — a CLS-safe responsive React `<Image>`. A thin wrapper over
2
+ * `@nifrajs/web-react/image` - a CLS-safe responsive React `<Image>`. A thin wrapper over
3
3
  * `resolveImage` from `@nifrajs/image`: it computes `src`/`srcSet`/`sizes`/`width`/`height`/`loading`/
4
4
  * `decoding`/`fetchpriority` and renders a plain `<img>`, forwarding any extra DOM props
5
5
  * (`className`, `style`, `id`, event handlers, `data-*`, …). Resizing is delegated to the `loader`
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { RenderAdapter } from "@nifrajs/web";
2
- /** The React server render adapter — pass to @nifrajs/web's `renderPage`. */
2
+ /** The React server render adapter - pass to @nifrajs/web's `renderPage`. */
3
3
  export declare const reactAdapter: RenderAdapter;
4
4
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
1
  /**
2
- * @nifrajs/web-react — the React render adapter for @nifrajs/web (server side). Streaming SSR via
2
+ * @nifrajs/web-react - the React render adapter for @nifrajs/web (server side). Streaming SSR via
3
3
  * `renderToReadableStream`; the layout-chain fold is in `./compose`. Client hydration lives in
4
- * `@nifrajs/web-react/client`. React's JSX is Bun-native — no build plugin needed.
4
+ * `@nifrajs/web-react/client`. React's JSX is Bun-native - no build plugin needed.
5
5
  */
6
6
  import { compose } from "./compose.js";
7
7
  import { reactDomServer } from "./react-dom-server.js";
8
- /** The React server render adapter — pass to @nifrajs/web's `renderPage`. */
8
+ /** The React server render adapter - pass to @nifrajs/web's `renderPage`. */
9
9
  export const reactAdapter = {
10
10
  // Synchronous one-pass render for non-deferred pages (renderPage's buffered fast path). React's
11
11
  // `renderToString` emits the same hydration-compatible markup as the Fizz stream for non-Suspense
12
- // content and is markedly cheaper than `renderToReadableStream` — most visibly on Bun, where Fizz's
12
+ // content and is markedly cheaper than `renderToReadableStream` - most visibly on Bun, where Fizz's
13
13
  // streaming machinery is the heaviest. A page that defer()s/Suspends takes `renderToStream` below.
14
14
  //
15
15
  // Async because the `react-dom/server` module is resolved lazily (from the consumer app's node_modules
16
- // under Bun runtime SSR — see ./react-dom-server). `RenderAdapter.renderToString` permits a Promise;
16
+ // under Bun runtime SSR - see ./react-dom-server). `RenderAdapter.renderToString` permits a Promise;
17
17
  // renderPage awaits it.
18
18
  async renderToString(chain, props) {
19
19
  const { renderToString } = await reactDomServer();
@@ -21,13 +21,13 @@ export const reactAdapter = {
21
21
  },
22
22
  async renderToStream(chain, props) {
23
23
  // Resolves a Web `ReadableStream<Uint8Array>` once the shell is renderable; Suspense
24
- // boundaries stream as they resolve. No `bootstrapModules` — nifra injects the client entry in
24
+ // boundaries stream as they resolve. No `bootstrapModules` - nifra injects the client entry in
25
25
  // the document tail. React's default `onError` logs to console.error (errors aren't swallowed).
26
26
  const { renderToReadableStream } = await reactDomServer();
27
27
  return renderToReadableStream(compose(chain, props));
28
28
  },
29
29
  // React reconciles against the existing DOM on hydrate, so no per-document bootstrap
30
- // script is needed (contrast Solid's generateHydrationScript) — the seam allows both.
30
+ // script is needed (contrast Solid's generateHydrationScript) - the seam allows both.
31
31
  hydrationHead() {
32
32
  return "";
33
33
  },
package/dist/island.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { IslandStrategy } from "@nifrajs/web/islands";
2
2
  /**
3
- * `@nifrajs/web-react/island` — the `<Island>` marker for no-framework islands. Server-renders its
3
+ * `@nifrajs/web-react/island` - the `<Island>` marker for no-framework islands. Server-renders its
4
4
  * children inside a `<nifra-island>` element that the framework-agnostic `mountIslands` runtime
5
- * (`@nifrajs/web/islands`) picks up on the client. Imports only `react` (+ a type) — no `react-dom`,
5
+ * (`@nifrajs/web/islands`) picks up on the client. Imports only `react` (+ a type) - no `react-dom`,
6
6
  * no JSX (the package builds with plain `tsc`).
7
7
  *
8
8
  * Use on a route with `export const hydrate = false`: the page ships zero framework JS, and only the
@@ -17,7 +17,7 @@ export interface IslandProps {
17
17
  readonly props?: unknown;
18
18
  /** When the enhancer runs (default `load`). `visible` (IntersectionObserver) wins TTI on long pages. */
19
19
  readonly strategy?: IslandStrategy;
20
- /** The island's server-rendered content — real HTML, present with JS off. */
20
+ /** The island's server-rendered content - real HTML, present with JS off. */
21
21
  readonly children?: ReactNode;
22
22
  }
23
23
  /** Render a `<nifra-island>` marker around server-rendered `children`. The client enhancer mounts the
package/dist/island.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * `@nifrajs/web-react/island` — the `<Island>` marker for no-framework islands. Server-renders its
2
+ * `@nifrajs/web-react/island` - the `<Island>` marker for no-framework islands. Server-renders its
3
3
  * children inside a `<nifra-island>` element that the framework-agnostic `mountIslands` runtime
4
- * (`@nifrajs/web/islands`) picks up on the client. Imports only `react` (+ a type) — no `react-dom`,
4
+ * (`@nifrajs/web/islands`) picks up on the client. Imports only `react` (+ a type) - no `react-dom`,
5
5
  * no JSX (the package builds with plain `tsc`).
6
6
  *
7
7
  * Use on a route with `export const hydrate = false`: the page ships zero framework JS, and only the
package/dist/query.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@nifrajs/web-react/query` — React bindings for the keyed query-cache + mutations: `useQuery`,
2
+ * `@nifrajs/web-react/query` - React bindings for the keyed query-cache + mutations: `useQuery`,
3
3
  * `useInfiniteQuery`, `useMutation`, `useQueryClient`, `QueryClientProvider`, and the SSR
4
4
  * `HydrationBoundary` (+ `dehydrate` re-exported). A drop-in for the TanStack Query surface,
5
5
  * backed by `@nifrajs/web`'s agnostic engine. Imports only `react` + `@nifrajs/web` (never `react-dom/*`),
@@ -7,13 +7,13 @@
7
7
  *
8
8
  * Resolution order for the client a hook uses: a `QueryClientProvider` in the tree (required for SSR
9
9
  * dehydrate/hydrate and for tests), else a lazily-created **client-side** module singleton (the simple
10
- * client-only app — the `typeof window` guard means the server has none, so hooks render idle/pending
10
+ * client-only app - the `typeof window` guard means the server has none, so hooks render idle/pending
11
11
  * and the first client render matches for a clean hydration).
12
12
  */
13
13
  import { type DehydratedState, type InfiniteData, type InfiniteQueryOptions, type MutationCallbacks, type MutationState, type QueryClient, type QueryOptions, type QueryState } from "@nifrajs/web";
14
14
  import { type ReactNode } from "react";
15
15
  export type { DehydratedState } from "@nifrajs/web";
16
- /** Provide a {@link QueryClient} to the tree — required for SSR dehydrate/hydrate and for tests; a
16
+ /** Provide a {@link QueryClient} to the tree - required for SSR dehydrate/hydrate and for tests; a
17
17
  * client-only app can omit it and rely on the built-in client-side singleton. */
18
18
  export declare function QueryClientProvider(props: {
19
19
  readonly client: QueryClient;
@@ -24,12 +24,12 @@ export declare function QueryClientProvider(props: {
24
24
  export declare function useQueryClient(): QueryClient;
25
25
  /** Options for {@link useQuery}. */
26
26
  export interface UseQueryOptions extends QueryOptions {
27
- /** When `false`, don't fetch (the query stays idle) — for dependent queries. Default `true`. */
27
+ /** When `false`, don't fetch (the query stays idle) - for dependent queries. Default `true`. */
28
28
  readonly enabled?: boolean;
29
29
  }
30
30
  /** A query's reactive {@link QueryState} plus `isPending` + `refetch`. */
31
31
  export interface UseQueryResult<T> extends QueryState<T> {
32
- /** `status === "pending"` — no data yet (initial load). */
32
+ /** `status === "pending"` - no data yet (initial load). */
33
33
  readonly isPending: boolean;
34
34
  /** `status === "error"`. */
35
35
  readonly isError: boolean;
@@ -54,7 +54,7 @@ export interface UseMutationResult<TData, TVariables> extends MutationState<TDat
54
54
  readonly isSuccess: boolean;
55
55
  /** Fire-and-forget: runs the mutation and swallows rejection (read `error`/`isError` for failures). */
56
56
  readonly mutate: (variables: TVariables) => void;
57
- /** Run the mutation and return the promise (rejects on failure) — for `await`. */
57
+ /** Run the mutation and return the promise (rejects on failure) - for `await`. */
58
58
  readonly mutateAsync: (variables: TVariables) => Promise<TData>;
59
59
  /** Reset back to idle. */
60
60
  readonly reset: () => void;
@@ -66,7 +66,7 @@ export interface UseMutationResult<TData, TVariables> extends MutationState<TDat
66
66
  * callbacks re-bind each render.
67
67
  */
68
68
  export declare function useMutation<TData, TVariables = void>(fn: (variables: TVariables) => Promise<TData>, callbacks?: MutationCallbacks<TData, TVariables>): UseMutationResult<TData, TVariables>;
69
- /** Options for {@link useInfiniteQuery} — the engine's {@link InfiniteQueryOptions} plus `enabled`. */
69
+ /** Options for {@link useInfiniteQuery} - the engine's {@link InfiniteQueryOptions} plus `enabled`. */
70
70
  export interface UseInfiniteQueryOptions<T, P> extends InfiniteQueryOptions<T, P> {
71
71
  readonly enabled?: boolean;
72
72
  }
@@ -88,7 +88,7 @@ export interface UseInfiniteQueryResult<T, P> extends QueryState<InfiniteData<T,
88
88
  */
89
89
  export declare function useInfiniteQuery<T, P>(key: unknown, fn: (pageParam: P) => Promise<T>, options: UseInfiniteQueryOptions<T, P>): UseInfiniteQueryResult<T, P>;
90
90
  /**
91
- * Seed the context's {@link QueryClient} from a server {@link dehydrate} snapshot — the SSR data bridge.
91
+ * Seed the context's {@link QueryClient} from a server {@link dehydrate} snapshot - the SSR data bridge.
92
92
  * Wrap the app (inside `QueryClientProvider`) so server-prefetched queries are in the cache before the
93
93
  * first client render, avoiding a loading flash. Hydration runs during render (idempotent, fresher-wins),
94
94
  * so the data is available synchronously to child `useQuery`s.