@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/dist/query.js 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,7 +7,7 @@
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 { createMutation, createQueryClient, } from "@nifrajs/web";
@@ -35,7 +35,7 @@ const NOOP_CLIENT = {
35
35
  hydrate: () => { },
36
36
  };
37
37
  const QueryClientContext = createContext(undefined);
38
- /** Provide a {@link QueryClient} to the tree — required for SSR dehydrate/hydrate and for tests; a
38
+ /** Provide a {@link QueryClient} to the tree - required for SSR dehydrate/hydrate and for tests; a
39
39
  * client-only app can omit it and rely on the built-in client-side singleton. */
40
40
  export function QueryClientProvider(props) {
41
41
  return createElement(QueryClientContext.Provider, { value: props.client }, props.children);
@@ -91,7 +91,7 @@ export function useQuery(key, fn, options) {
91
91
  // A disabled query still binds a handle (so it re-renders when re-enabled), but never fetches.
92
92
  const handle = client.query(key, fn, queryOpts);
93
93
  // Server snapshot = the handle's own snapshot: without a provider the client is the NOOP one (idle),
94
- // but WITH a hydrated provider client it returns the server-seeded data — so a HydrationBoundary-fed
94
+ // but WITH a hydrated provider client it returns the server-seeded data - so a HydrationBoundary-fed
95
95
  // query renders its data during SSR and the first client render matches (no loading flash, no drift).
96
96
  const state = useSyncExternalStore(handle.subscribe, handle.snapshot, handle.snapshot);
97
97
  useEffect(() => {
@@ -159,7 +159,7 @@ export function useInfiniteQuery(key, fn, options) {
159
159
  };
160
160
  }
161
161
  /**
162
- * Seed the context's {@link QueryClient} from a server {@link dehydrate} snapshot — the SSR data bridge.
162
+ * Seed the context's {@link QueryClient} from a server {@link dehydrate} snapshot - the SSR data bridge.
163
163
  * Wrap the app (inside `QueryClientProvider`) so server-prefetched queries are in the cache before the
164
164
  * first client render, avoiding a loading flash. Hydration runs during render (idempotent, fresher-wins),
165
165
  * so the data is available synchronously to child `useQuery`s.
@@ -1,30 +1,30 @@
1
1
  /**
2
- * Resolve `react-dom/server` so it shares ONE React core with the route components — the fix for the
2
+ * Resolve `react-dom/server` so it shares ONE React core with the route components - the fix for the
3
3
  * dual-React SSR crash (`resolveDispatcher().useState` is null / "Invalid hook call: mismatching versions
4
4
  * of React and the renderer").
5
5
  *
6
6
  * WHY this exists: under Bun **runtime** SSR (`nifra dev`, `nifra start`, `nifra_render`, all in-process),
7
7
  * a static `import "react-dom/server"` in this adapter is resolved by Bun from THIS package's own
8
- * (symlinked) node_modules — which can be a DIFFERENT physical `react` than the one the consumer app's
8
+ * (symlinked) node_modules - which can be a DIFFERENT physical `react` than the one the consumer app's
9
9
  * route components import. Two React cores → two hook dispatchers → the renderer's dispatcher is the wrong
10
10
  * (or null) one → the crash. Resolving `react-dom/server` from the consumer **app root** instead makes
11
11
  * react-dom pull the app's `react` transitively, matching the components' `react`: a single core, a single
12
- * dispatcher, no crash. (Empirically verified against a two-copy install fixture — see
12
+ * dispatcher, no crash. (Empirically verified against a two-copy install fixture - see
13
13
  * test/dual-react.test.ts.)
14
14
  *
15
- * Guarding precisely so the BUILT path is untouched: a bundle is detected two ways — `Bun.resolveSync` is
15
+ * Guarding precisely so the BUILT path is untouched: a bundle is detected two ways - `Bun.resolveSync` is
16
16
  * unavailable (Node / Deno / Cloudflare / Vercel), OR `buildServer` tagged the output with
17
17
  * `process.env.NIFRA_SSR_BUNDLED` (a `target:"bun"` bundle DOES keep `Bun.resolveSync` under the Bun
18
18
  * runtime, so the resolver test alone can't see it). In either case the build already bundled+deduped a
19
19
  * single `react-dom` (buildServer's `reactDedupePlugin` pins `react`), so the static `import` is correct.
20
- * Re-rooting a bundle would instead re-import a SECOND react-dom from disk — a second React core whose hook
20
+ * Re-rooting a bundle would instead re-import a SECOND react-dom from disk - a second React core whose hook
21
21
  * dispatcher is null for the bundled components → the `…H.useRef of null` SSR crash. The app-root re-root
22
22
  * therefore runs ONLY under an UNBUNDLED Bun runtime (nifra dev/start, nifra_render), where the duplication
23
23
  * can occur, `Bun.resolveSync` exists, and no bundle marker is present.
24
24
  */
25
25
  import type { ReactNode } from "react";
26
26
  /** The slice of `react-dom/server` this adapter uses. Typed locally so the dynamic import (which Bun
27
- * resolves to an absolute path string) stays strict — no `any` crosses the boundary. */
27
+ * resolves to an absolute path string) stays strict - no `any` crosses the boundary. */
28
28
  export interface ReactDomServer {
29
29
  renderToString(node: ReactNode): string;
30
30
  renderToReadableStream(node: ReactNode): Promise<ReadableStream<Uint8Array>>;
@@ -66,7 +66,7 @@ export declare function assertSingleReactCore(reactDomServerPath: string, resolv
66
66
  */
67
67
  export declare function loadReactDomServer(resolve?: ResolveSync | undefined): Promise<ReactDomServer>;
68
68
  /**
69
- * The resolver `loadReactDomServer` uses by default, or `undefined` when re-rooting must NOT happen — a
69
+ * The resolver `loadReactDomServer` uses by default, or `undefined` when re-rooting must NOT happen - a
70
70
  * non-Bun host (no `Bun.resolveSync`; the static import is the only path) OR a BUNDLED SSR output.
71
71
  * `buildServer` defines `process.env.NIFRA_SSR_BUNDLED` to `"1"` in every bundle, where react-dom is
72
72
  * already inlined + deduped to the components' React (reactDedupePlugin); re-rooting there would re-import
@@ -1,23 +1,23 @@
1
1
  /**
2
- * Resolve `react-dom/server` so it shares ONE React core with the route components — the fix for the
2
+ * Resolve `react-dom/server` so it shares ONE React core with the route components - the fix for the
3
3
  * dual-React SSR crash (`resolveDispatcher().useState` is null / "Invalid hook call: mismatching versions
4
4
  * of React and the renderer").
5
5
  *
6
6
  * WHY this exists: under Bun **runtime** SSR (`nifra dev`, `nifra start`, `nifra_render`, all in-process),
7
7
  * a static `import "react-dom/server"` in this adapter is resolved by Bun from THIS package's own
8
- * (symlinked) node_modules — which can be a DIFFERENT physical `react` than the one the consumer app's
8
+ * (symlinked) node_modules - which can be a DIFFERENT physical `react` than the one the consumer app's
9
9
  * route components import. Two React cores → two hook dispatchers → the renderer's dispatcher is the wrong
10
10
  * (or null) one → the crash. Resolving `react-dom/server` from the consumer **app root** instead makes
11
11
  * react-dom pull the app's `react` transitively, matching the components' `react`: a single core, a single
12
- * dispatcher, no crash. (Empirically verified against a two-copy install fixture — see
12
+ * dispatcher, no crash. (Empirically verified against a two-copy install fixture - see
13
13
  * test/dual-react.test.ts.)
14
14
  *
15
- * Guarding precisely so the BUILT path is untouched: a bundle is detected two ways — `Bun.resolveSync` is
15
+ * Guarding precisely so the BUILT path is untouched: a bundle is detected two ways - `Bun.resolveSync` is
16
16
  * unavailable (Node / Deno / Cloudflare / Vercel), OR `buildServer` tagged the output with
17
17
  * `process.env.NIFRA_SSR_BUNDLED` (a `target:"bun"` bundle DOES keep `Bun.resolveSync` under the Bun
18
18
  * runtime, so the resolver test alone can't see it). In either case the build already bundled+deduped a
19
19
  * single `react-dom` (buildServer's `reactDedupePlugin` pins `react`), so the static `import` is correct.
20
- * Re-rooting a bundle would instead re-import a SECOND react-dom from disk — a second React core whose hook
20
+ * Re-rooting a bundle would instead re-import a SECOND react-dom from disk - a second React core whose hook
21
21
  * dispatcher is null for the bundled components → the `…H.useRef of null` SSR crash. The app-root re-root
22
22
  * therefore runs ONLY under an UNBUNDLED Bun runtime (nifra dev/start, nifra_render), where the duplication
23
23
  * can occur, `Bun.resolveSync` exists, and no bundle marker is present.
@@ -120,7 +120,7 @@ export async function loadReactDomServer(resolve = bunResolverFn()) {
120
120
  // Bun runtime SSR: re-root to the app's copy so react-dom shares the components' React. `react-dom`
121
121
  // is a PEER dependency of this adapter, so a correct install puts it at the app root and this
122
122
  // resolves. If it somehow doesn't (an unusual nested layout), fall through to the bundled specifier
123
- // rather than crashing — degraded (possible duplicate) but never a hard failure.
123
+ // rather than crashing - degraded (possible duplicate) but never a hard failure.
124
124
  try {
125
125
  const resolved = resolve("react-dom/server", appRoot());
126
126
  // Before returning the module, verify the react-dom we just re-rooted shares the components' React.
@@ -144,7 +144,7 @@ export async function loadReactDomServer(resolve = bunResolverFn()) {
144
144
  return (await import("react-dom/server"));
145
145
  }
146
146
  /**
147
- * The resolver `loadReactDomServer` uses by default, or `undefined` when re-rooting must NOT happen — a
147
+ * The resolver `loadReactDomServer` uses by default, or `undefined` when re-rooting must NOT happen - a
148
148
  * non-Bun host (no `Bun.resolveSync`; the static import is the only path) OR a BUNDLED SSR output.
149
149
  * `buildServer` defines `process.env.NIFRA_SSR_BUNDLED` to `"1"` in every bundle, where react-dom is
150
150
  * already inlined + deduped to the components' React (reactDedupePlugin); re-rooting there would re-import
package/dist/router.d.ts CHANGED
@@ -1,24 +1,30 @@
1
1
  /**
2
- * `@nifrajs/web-react/router` — React routing bindings over the agnostic `@nifrajs/web` router:
2
+ * `@nifrajs/web-react/router` - React routing bindings over the agnostic `@nifrajs/web` router:
3
3
  * `<Link>`/`<NavLink>`, `useNavigate`, `useParams`, `useLocation`, `useSearchParams`, and `<Navigate>`.
4
4
  *
5
5
  * These read the current route from a {@link RouterContext} that `compose` provides on BOTH the SSR
6
6
  * render and the client mount (seeded from the request match / router state respectively), so the read
7
7
  * hooks (`useParams`/`useLocation`/`useSearchParams`) are SSR-correct and hydrate with no mismatch.
8
8
  * Navigation goes through `@nifrajs/web`'s DOM-free navigate bridge (`getBrowserNavigate`, populated by
9
- * `installHistory`) — so this module imports only `react` (never `react-dom/*`), and a route component
9
+ * `installHistory`) - so this module imports only `react` (never `react-dom/*`), and a route component
10
10
  * can use these on the server and the client without dragging a DOM build into the wrong bundle. No JSX
11
11
  * (the package builds with plain `tsc`), so everything is `createElement`.
12
12
  */
13
- import { type NavigateOptions } from "@nifrajs/web";
13
+ import type { InferOutput, StandardSchemaV1 } from "@nifrajs/core/server";
14
+ import { type Blocker, type BlockerFunction, type NavigateFunction, type NavigateOptions } from "@nifrajs/web";
14
15
  import { type AnchorHTMLAttributes, type CSSProperties, type ReactNode } from "react";
16
+ export type { Blocker, BlockerFunction, BlockerState, NavigateFunction } from "@nifrajs/web";
15
17
  /** The current route the routing hooks read. Provided by `compose` on SSR + client mount alike. */
16
18
  export interface RouterContextValue {
17
19
  /** The matched route's decoded path params (`/users/:id` → `{ id: "7" }`). */
18
20
  readonly params: Readonly<Record<string, string>>;
19
- /** The current URL's `pathname + search` (no hash — the router never carries one). */
21
+ /** The current URL's `pathname + search` (no hash - the router never carries one). */
20
22
  readonly path: string;
21
- /** True while a client navigation (or revalidation) is in flight — the current route stays mounted
23
+ /** The route's typed, validated search params (the loader's `ctx.search`), derived from the URL via
24
+ * the shared `searchOf` on SSR + client alike, read by {@link useSearch}. `{}` when the route
25
+ * declares no `searchSchema` (then it is the raw parsed query) or outside a nifra route tree. */
26
+ readonly search: Record<string, unknown>;
27
+ /** True while a client navigation (or revalidation) is in flight - the current route stays mounted
22
28
  * until the new one is ready. Always `false` on SSR (loaders block before render). Drives loading UI
23
29
  * via {@link useNavigation}. */
24
30
  readonly pending: boolean;
@@ -26,16 +32,33 @@ export interface RouterContextValue {
26
32
  * during a same-route revalidation). Powers {@link NavLink}'s per-link `isPending`. */
27
33
  readonly pendingPath?: string | undefined;
28
34
  }
29
- /** Router context. The default ({} params, "" path) is what a component sees when rendered outside a
30
- * nifra route tree — the hooks stay defined (no throw) so a stray `useParams` degrades gracefully. */
35
+ /** Router context. The default ({} params, "" path, {} search) is what a component sees when rendered
36
+ * outside a nifra route tree (the hooks stay defined, no throw, so a stray `useParams` degrades
37
+ * gracefully). */
31
38
  export declare const RouterContext: import("react").Context<RouterContextValue>;
32
39
  /**
33
- * The matched route's decoded path params — `/users/:id` on `/users/7` → `{ id: "7" }`. SSR-correct:
40
+ * The matched route's decoded path params - `/users/:id` on `/users/7` → `{ id: "7" }`. SSR-correct:
34
41
  * `compose` provides the same value server-side (from the request match) and client-side (from router
35
42
  * state), so a param rendered into markup doesn't flash on hydration.
36
43
  */
37
44
  export declare function useParams<T extends Record<string, string | undefined> = Record<string, string>>(): Readonly<T>;
38
- /** The parsed current location. `hash` is always `""` — the fragment is client-only and never reaches
45
+ /**
46
+ * The route's typed, validated search params: the SAME value the loader received as `ctx.search`.
47
+ * SSR-correct: `compose` provides it from `searchOf(searchSchema, url.search)` server-side and from the
48
+ * identical derivation on the client mount, so a value rendered from it doesn't flash on hydration.
49
+ * Hostile input already failed closed to the schema's defaults at match time, so a component never
50
+ * parses `window.location.search` or guards against a bad query.
51
+ *
52
+ * Pass the route's `searchSchema` as the type argument to get its output type; bare, it's the raw parsed
53
+ * query (`Record<string, unknown>`), which is also what a route without a `searchSchema` yields.
54
+ *
55
+ * ```tsx
56
+ * export const searchSchema = v.object({ page: v.optional(v.fallback(v.number(), 1), 1) })
57
+ * const { page } = useSearch<typeof searchSchema>() // page: number
58
+ * ```
59
+ */
60
+ export declare function useSearch<Schema extends StandardSchemaV1 | undefined = undefined>(): Schema extends StandardSchemaV1 ? InferOutput<Schema> : Record<string, unknown>;
61
+ /** The parsed current location. `hash` is always `""` - the fragment is client-only and never reaches
39
62
  * the router state / server, so exposing a live hash would hydration-mismatch; read `window.location.hash`
40
63
  * directly (in an effect) if you truly need it. */
41
64
  export interface Location {
@@ -71,13 +94,38 @@ export interface Navigation {
71
94
  export declare function useNavigation(): Navigation;
72
95
  /** Convenience boolean form of {@link useNavigation}: `true` while a client navigation is in flight. */
73
96
  export declare function usePending(): boolean;
74
- /** A programmatic navigate: a string path (push, or replace via `{ replace: true }`) or a history delta
75
- * (`-1`/`1`). A no-op on the server / before hydration (a render-time navigate isn't valid — use
76
- * {@link Navigate}, which navigates in an effect). */
77
- export type NavigateFunction = (to: string | number, options?: NavigateOptions) => void;
78
- /** Get the {@link NavigateFunction}. Stable across renders; resolves the browser navigate at call time
79
- * (so it works as soon as `installHistory` has run, and no-ops before then / on the server). */
97
+ /** Get the {@link NavigateFunction} (a string path, a history delta, or a typed `{ to, search }` object;
98
+ * a render-time navigate isn't valid - use {@link Navigate}, which navigates in an effect). Stable across
99
+ * renders; resolves the browser navigate at call time (so it works as soon as `installHistory` has run,
100
+ * and no-ops before then / on the server). */
80
101
  export declare function useNavigate(): NavigateFunction;
102
+ /**
103
+ * Guard navigation away from a page with unsaved work, confirming with your OWN async UI. Mirrors
104
+ * react-router's `useBlocker`: pass a boolean (`useBlocker(isDirty)`) or a predicate
105
+ * `({ currentLocation, nextLocation }) => boolean`, and get back a {@link Blocker}. When a navigation
106
+ * (a `<Link>`/anchor click, `useNavigate`, or a browser back/forward) is intercepted, `blocker.state`
107
+ * becomes `"blocked"` and `proceed`/`reset` go live - render a dialog and call `proceed()` to continue
108
+ * or `reset()` to stay put. It also arms the browser's native "Leave site?" prompt on tab close / reload.
109
+ * Idle (never blocks, `proceed`/`reset` are `undefined`) on the server and before hydration, so it's
110
+ * SSR-safe and hydration-stable.
111
+ *
112
+ * ```tsx
113
+ * const blocker = useBlocker(form.isDirty)
114
+ * return (
115
+ * <>
116
+ * <MyForm />
117
+ * {blocker.state === "blocked" && (
118
+ * <ConfirmDialog
119
+ * onCancel={blocker.reset}
120
+ * onConfirm={blocker.proceed}
121
+ * message="Discard unsaved changes?"
122
+ * />
123
+ * )}
124
+ * </>
125
+ * )
126
+ * ```
127
+ */
128
+ export declare function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker;
81
129
  /** The value forms `setSearchParams` accepts. */
82
130
  export type SearchParamsInit = URLSearchParams | Record<string, string | readonly string[]> | string;
83
131
  /** Set the query string. Accepts a `URLSearchParams`, a record, a raw string, or an updater of the
@@ -99,7 +147,7 @@ export interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>,
99
147
  * A client-navigating anchor. Renders a real `<a href={to}>` (so it's a working link before hydration
100
148
  * and for right-click / open-in-new-tab), and on a plain left-click navigates through the router
101
149
  * instead of a full reload. Calling `navigate` + `preventDefault` here means `installHistory`'s
102
- * document-level click handler sees `defaultPrevented` and stands down — exactly one navigation.
150
+ * document-level click handler sees `defaultPrevented` and stands down - exactly one navigation.
103
151
  */
104
152
  export declare const Link: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
105
153
  /** The state a {@link NavLink}'s function-form `className`/`style`/`children` receive. */
@@ -110,7 +158,7 @@ export interface NavLinkRenderProps {
110
158
  * `false` on SSR and when idle. Use it to show a per-link spinner during the transition. */
111
159
  readonly isPending: boolean;
112
160
  }
113
- /** {@link NavLink} props — like {@link LinkProps}, but `className`/`style`/`children` may be functions
161
+ /** {@link NavLink} props - like {@link LinkProps}, but `className`/`style`/`children` may be functions
114
162
  * of the active state, and `end`/`caseSensitive` tune matching. */
115
163
  export interface NavLinkProps extends Omit<LinkProps, "className" | "style" | "children"> {
116
164
  /** Match the full path exactly instead of as a prefix (use for `to="/"` so it isn't always active). */
@@ -134,7 +182,7 @@ export interface NavigateProps {
134
182
  readonly replace?: boolean;
135
183
  }
136
184
  /**
137
- * Declaratively navigate on mount — the component analogue of `useNavigate` (e.g. a guard that renders
185
+ * Declaratively navigate on mount - the component analogue of `useNavigate` (e.g. a guard that renders
138
186
  * `<Navigate to="/login" replace />`). Navigates in an effect, so it's a safe no-op during SSR (renders
139
187
  * `null`); the redirect happens once on the client after hydration.
140
188
  */
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
package/dist/router.js CHANGED
@@ -1,24 +1,27 @@
1
1
  /**
2
- * `@nifrajs/web-react/router` — React routing bindings over the agnostic `@nifrajs/web` router:
2
+ * `@nifrajs/web-react/router` - React routing bindings over the agnostic `@nifrajs/web` router:
3
3
  * `<Link>`/`<NavLink>`, `useNavigate`, `useParams`, `useLocation`, `useSearchParams`, and `<Navigate>`.
4
4
  *
5
5
  * These read the current route from a {@link RouterContext} that `compose` provides on BOTH the SSR
6
6
  * render and the client mount (seeded from the request match / router state respectively), so the read
7
7
  * hooks (`useParams`/`useLocation`/`useSearchParams`) are SSR-correct and hydrate with no mismatch.
8
8
  * Navigation goes through `@nifrajs/web`'s DOM-free navigate bridge (`getBrowserNavigate`, populated by
9
- * `installHistory`) — so this module imports only `react` (never `react-dom/*`), and a route component
9
+ * `installHistory`) - so this module imports only `react` (never `react-dom/*`), and a route component
10
10
  * can use these on the server and the client without dragging a DOM build into the wrong bundle. No JSX
11
11
  * (the package builds with plain `tsc`), so everything is `createElement`.
12
12
  */
13
- import { getBrowserNavigate } from "@nifrajs/web";
14
- import { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useMemo, } from "react";
15
- // Frozen empty params so the default context value has a stable reference (no needless re-renders).
13
+ import { getBrowserNavigate, IDLE_BLOCKER, registerBlocker, resolveNavigate, } from "@nifrajs/web";
14
+ import { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
15
+ // Frozen empty params/search so the default context value has a stable reference (no needless re-renders).
16
16
  const EMPTY_PARAMS = Object.freeze({});
17
- /** Router context. The default ({} params, "" path) is what a component sees when rendered outside a
18
- * nifra route tree — the hooks stay defined (no throw) so a stray `useParams` degrades gracefully. */
17
+ const EMPTY_SEARCH = Object.freeze({});
18
+ /** Router context. The default ({} params, "" path, {} search) is what a component sees when rendered
19
+ * outside a nifra route tree (the hooks stay defined, no throw, so a stray `useParams` degrades
20
+ * gracefully). */
19
21
  export const RouterContext = createContext({
20
22
  params: EMPTY_PARAMS,
21
23
  path: "",
24
+ search: EMPTY_SEARCH,
22
25
  pending: false,
23
26
  });
24
27
  /** Split a `pathname + search` into its parts. `search` keeps its leading `?` (like `location.search`);
@@ -30,13 +33,31 @@ function splitPath(path) {
30
33
  : { pathname: path.slice(0, q), search: path.slice(q) };
31
34
  }
32
35
  /**
33
- * The matched route's decoded path params — `/users/:id` on `/users/7` → `{ id: "7" }`. SSR-correct:
36
+ * The matched route's decoded path params - `/users/:id` on `/users/7` → `{ id: "7" }`. SSR-correct:
34
37
  * `compose` provides the same value server-side (from the request match) and client-side (from router
35
38
  * state), so a param rendered into markup doesn't flash on hydration.
36
39
  */
37
40
  export function useParams() {
38
41
  return useContext(RouterContext).params;
39
42
  }
43
+ /**
44
+ * The route's typed, validated search params: the SAME value the loader received as `ctx.search`.
45
+ * SSR-correct: `compose` provides it from `searchOf(searchSchema, url.search)` server-side and from the
46
+ * identical derivation on the client mount, so a value rendered from it doesn't flash on hydration.
47
+ * Hostile input already failed closed to the schema's defaults at match time, so a component never
48
+ * parses `window.location.search` or guards against a bad query.
49
+ *
50
+ * Pass the route's `searchSchema` as the type argument to get its output type; bare, it's the raw parsed
51
+ * query (`Record<string, unknown>`), which is also what a route without a `searchSchema` yields.
52
+ *
53
+ * ```tsx
54
+ * export const searchSchema = v.object({ page: v.optional(v.fallback(v.number(), 1), 1) })
55
+ * const { page } = useSearch<typeof searchSchema>() // page: number
56
+ * ```
57
+ */
58
+ export function useSearch() {
59
+ return useContext(RouterContext).search;
60
+ }
40
61
  /** The current {@link Location} (`pathname`/`search`/`hash`), derived from the router context. */
41
62
  export function useLocation() {
42
63
  const { path } = useContext(RouterContext);
@@ -69,15 +90,59 @@ export function useNavigation() {
69
90
  export function usePending() {
70
91
  return useContext(RouterContext).pending;
71
92
  }
72
- /** Get the {@link NavigateFunction}. Stable across renders; resolves the browser navigate at call time
73
- * (so it works as soon as `installHistory` has run, and no-ops before then / on the server). */
93
+ /** Get the {@link NavigateFunction} (a string path, a history delta, or a typed `{ to, search }` object;
94
+ * a render-time navigate isn't valid - use {@link Navigate}, which navigates in an effect). Stable across
95
+ * renders; resolves the browser navigate at call time (so it works as soon as `installHistory` has run,
96
+ * and no-ops before then / on the server). */
74
97
  export function useNavigate() {
75
98
  return useCallback((to, options) => {
76
99
  const navigate = getBrowserNavigate();
77
- if (navigate !== undefined)
78
- navigate(to, options);
100
+ if (navigate === undefined)
101
+ return;
102
+ const resolved = resolveNavigate(to, options);
103
+ navigate(resolved.to, resolved.options);
79
104
  }, []);
80
105
  }
106
+ /**
107
+ * Guard navigation away from a page with unsaved work, confirming with your OWN async UI. Mirrors
108
+ * react-router's `useBlocker`: pass a boolean (`useBlocker(isDirty)`) or a predicate
109
+ * `({ currentLocation, nextLocation }) => boolean`, and get back a {@link Blocker}. When a navigation
110
+ * (a `<Link>`/anchor click, `useNavigate`, or a browser back/forward) is intercepted, `blocker.state`
111
+ * becomes `"blocked"` and `proceed`/`reset` go live - render a dialog and call `proceed()` to continue
112
+ * or `reset()` to stay put. It also arms the browser's native "Leave site?" prompt on tab close / reload.
113
+ * Idle (never blocks, `proceed`/`reset` are `undefined`) on the server and before hydration, so it's
114
+ * SSR-safe and hydration-stable.
115
+ *
116
+ * ```tsx
117
+ * const blocker = useBlocker(form.isDirty)
118
+ * return (
119
+ * <>
120
+ * <MyForm />
121
+ * {blocker.state === "blocked" && (
122
+ * <ConfirmDialog
123
+ * onCancel={blocker.reset}
124
+ * onConfirm={blocker.proceed}
125
+ * message="Discard unsaved changes?"
126
+ * />
127
+ * )}
128
+ * </>
129
+ * )
130
+ * ```
131
+ */
132
+ export function useBlocker(shouldBlock) {
133
+ const [blocker, setBlocker] = useState(IDLE_BLOCKER);
134
+ // Track the latest predicate in a ref (updated every render) so the single registration always sees
135
+ // current component state (the dirty flag) WITHOUT re-registering - re-registering mid-prompt drops it.
136
+ const shouldBlockRef = useRef(shouldBlock);
137
+ shouldBlockRef.current = shouldBlock;
138
+ // Register once on mount; the returned unregister is the effect cleanup. A boolean reads as itself, a
139
+ // function is called. A no-op before `installHistory` has run (blocker stays idle → native navigation).
140
+ useEffect(() => registerBlocker((args) => {
141
+ const current = shouldBlockRef.current;
142
+ return typeof current === "function" ? current(args) : current;
143
+ }, setBlocker), []);
144
+ return blocker;
145
+ }
81
146
  function toSearchParams(init) {
82
147
  if (init instanceof URLSearchParams)
83
148
  return init;
@@ -109,7 +174,7 @@ export function useSearchParams() {
109
174
  }, [navigate, pathname, search]);
110
175
  return [searchParams, setSearchParams];
111
176
  }
112
- /** A left-click with no modifier and no new-tab target — the only click a client router should
177
+ /** A left-click with no modifier and no new-tab target - the only click a client router should
113
178
  * intercept (Cmd/Ctrl/Shift/Alt or a `_blank` target means the user wants native behavior). */
114
179
  function isPlainLeftClick(event, target) {
115
180
  if (event.button !== 0)
@@ -122,7 +187,7 @@ function isPlainLeftClick(event, target) {
122
187
  * A client-navigating anchor. Renders a real `<a href={to}>` (so it's a working link before hydration
123
188
  * and for right-click / open-in-new-tab), and on a plain left-click navigates through the router
124
189
  * instead of a full reload. Calling `navigate` + `preventDefault` here means `installHistory`'s
125
- * document-level click handler sees `defaultPrevented` and stands down — exactly one navigation.
190
+ * document-level click handler sees `defaultPrevented` and stands down - exactly one navigation.
126
191
  */
127
192
  export const Link = forwardRef(function Link({ to, replace, onClick, target, ...rest }, ref) {
128
193
  const handleClick = (event) => {
@@ -187,7 +252,7 @@ function matchesPrefix(current, target) {
187
252
  return current.startsWith(target === "/" ? "/" : `${target}/`);
188
253
  }
189
254
  /**
190
- * Declaratively navigate on mount — the component analogue of `useNavigate` (e.g. a guard that renders
255
+ * Declaratively navigate on mount - the component analogue of `useNavigate` (e.g. a guard that renders
191
256
  * `<Navigate to="/login" replace />`). Navigates in an effect, so it's a safe no-op during SSR (renders
192
257
  * `null`); the redirect happens once on the client after hydration.
193
258
  */
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nifrajs/web-react",
3
- "version": "2.2.0",
4
- "description": "React render adapter for @nifrajs/web — SSR + hydration (Bun-native JSX, no Babel).",
3
+ "version": "2.4.0",
4
+ "description": "React render adapter for @nifrajs/web - SSR + hydration (Bun-native JSX, no Babel).",
5
5
  "keywords": [
6
6
  "bun",
7
7
  "typescript",
@@ -65,6 +65,11 @@
65
65
  "bun": "./src/content.ts",
66
66
  "types": "./dist/content.d.ts",
67
67
  "default": "./dist/content.js"
68
+ },
69
+ "./fn": {
70
+ "bun": "./src/fn.ts",
71
+ "types": "./dist/fn.d.ts",
72
+ "default": "./dist/fn.js"
68
73
  }
69
74
  },
70
75
  "files": [
@@ -80,10 +85,10 @@
80
85
  "access": "public"
81
86
  },
82
87
  "dependencies": {
83
- "@nifrajs/core": "2.2.0",
84
- "@nifrajs/i18n": "2.2.0",
85
- "@nifrajs/image": "2.2.0",
86
- "@nifrajs/web": "2.2.0"
88
+ "@nifrajs/core": "2.4.0",
89
+ "@nifrajs/i18n": "2.4.0",
90
+ "@nifrajs/image": "2.4.0",
91
+ "@nifrajs/web": "2.4.0"
87
92
  },
88
93
  "peerDependencies": {
89
94
  "react": "^19.0.0",
package/src/await.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 { Component, createElement, type ReactNode, Suspense, use } from "react"
14
14
 
package/src/client.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { MountRouterOptions, RenderProps } from "@nifrajs/web"
1
+ import { type MountRouterOptions, type RenderProps, searchOfChain } from "@nifrajs/web"
2
2
  /**
3
- * @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;
4
4
  * `mountRouter` hydrates a stateful Router that subscribes to the agnostic store (via
5
5
  * `useSyncExternalStore`) and re-renders the matched chain on every client navigation (no full
6
6
  * reload). Kept in its own entry so server code stays out of the client bundle.
@@ -10,7 +10,7 @@ import { hydrateRoot } from "react-dom/client"
10
10
  import { compose } from "./compose.ts"
11
11
  import { setMountedRouter } from "./fetcher.ts"
12
12
 
13
- // The `_error` boundary chain element — defined in its own (react-dom-free) module, re-exported here so
13
+ // The `_error` boundary chain element - defined in its own (react-dom-free) module, re-exported here so
14
14
  // nifra's client codegen resolves it from `@nifrajs/web-react/client` alongside `mountRouter`.
15
15
  export { errorBoundary } from "./error.ts"
16
16
 
@@ -21,25 +21,31 @@ export function hydrate(chain: readonly unknown[], props: RenderProps, container
21
21
 
22
22
  /**
23
23
  * Hydrate a stateful React Router. `useSyncExternalStore` subscribes to the agnostic store and
24
- * re-renders the matched layout chain on each store change — so client navigations swap routes
24
+ * re-renders the matched layout chain on each store change - so client navigations swap routes
25
25
  * without a full reload. `getServerSnapshot` (3rd arg) returns the initial state, matching the
26
26
  * SSR markup on hydration.
27
27
  */
28
28
  export function mountRouter(options: MountRouterOptions): void {
29
- const { router, routes, container } = options
29
+ const { router, routes, searchSchemas, container } = options
30
30
  setMountedRouter(router) // expose it to useFetcher/useFetchers (same page, client-only)
31
31
  const Router: FunctionComponent = () => {
32
32
  const state = useSyncExternalStore(router.subscribe, router.snapshot, router.snapshot)
33
+ // Derive this route's typed `search` from the URL query + the route's schema CHAIN (layout schemas +
34
+ // page, merged page-wins), the SAME `searchOfChain` the server ran, so `useSearch` reads an identical
35
+ // value and hydrates with no drift.
36
+ const q = state.path.indexOf("?")
37
+ const rawSearch = q === -1 ? "" : state.path.slice(q)
33
38
  return compose(routes[state.routeId] ?? [], {
34
39
  data: state.data,
35
40
  actionData: state.actionData,
36
41
  pending: state.pending,
37
42
  ...(state.pendingPath !== undefined ? { pendingPath: state.pendingPath } : {}),
38
- // `params`/`path` feed the routing hooks (useParams/useLocation) via compose's RouterContext —
43
+ // `params`/`path` feed the routing hooks (useParams/useLocation) via compose's RouterContext -
39
44
  // sourced from router state here, matching the SSR render's request-derived values on hydration.
40
45
  params: state.params,
41
46
  path: state.path,
42
- // The in-flight submission (for optimistic UI) — spread only when present.
47
+ search: searchOfChain(searchSchemas?.[state.routeId] ?? [], rawSearch),
48
+ // The in-flight submission (for optimistic UI) - spread only when present.
43
49
  ...(state.submission ? { submission: state.submission } : {}),
44
50
  })
45
51
  }