@rangojs/router 0.29.0 → 0.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rango.js +1 -1
- package/dist/types/browser/react/use-action.d.ts +3 -2
- package/dist/types/browser/react/use-handle.d.ts +2 -1
- package/dist/types/browser/react/use-route-state.d.ts +45 -0
- package/dist/types/browser/types.d.ts +8 -4
- package/dist/types/suspense-audit.d.ts +19 -1
- package/dist/types/testing/render-route.d.ts +7 -7
- package/dist/types/vite/discovery/build-versions.d.ts +17 -13
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +1 -1
- package/dist/vite/index.js +87 -68
- package/package.json +1 -1
- package/skills/client-urls/SKILL.md +2 -6
- package/skills/hooks/handle-and-actions.md +9 -2
- package/skills/hooks/navigation.md +3 -3
- package/skills/hooks/urls.md +1 -0
- package/skills/testing/client-components.md +1 -1
- package/skills/testing/response-routes.md +3 -2
- package/src/browser/event-controller.ts +54 -17
- package/src/browser/react/use-action.ts +3 -2
- package/src/browser/react/use-handle.ts +6 -1
- package/src/browser/react/use-navigation.ts +16 -42
- package/src/browser/react/use-params.ts +6 -35
- package/src/browser/react/use-pathname.ts +3 -32
- package/src/browser/react/use-route-state.ts +141 -0
- package/src/browser/react/use-search-params.ts +7 -40
- package/src/browser/types.ts +8 -4
- package/src/suspense-audit.ts +58 -11
- package/src/testing/render-route.tsx +20 -14
- package/src/vite/discovery/build-versions.ts +67 -26
- package/src/vite/plugins/stable-rsc-output.ts +1 -1
package/dist/bin/rango.js
CHANGED
|
@@ -1644,7 +1644,7 @@ var init_package = __esm({
|
|
|
1644
1644
|
"package.json"() {
|
|
1645
1645
|
package_default = {
|
|
1646
1646
|
name: "@rangojs/router",
|
|
1647
|
-
version: "0.
|
|
1647
|
+
version: "0.30.1",
|
|
1648
1648
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1649
1649
|
keywords: [
|
|
1650
1650
|
"react",
|
|
@@ -13,11 +13,12 @@ export type ServerActionFunction = ((...args: any[]) => Promise<any>) & {
|
|
|
13
13
|
* tracks the state of individual server action invocations.
|
|
14
14
|
*
|
|
15
15
|
* Uses the event controller for reactive state management.
|
|
16
|
-
* State is derived from the
|
|
16
|
+
* State is derived from the calls the controller tracks: those in flight,
|
|
17
|
+
* and each action's last settled call.
|
|
17
18
|
*
|
|
18
19
|
* Features:
|
|
19
20
|
* - Tracks action lifecycle: idle → loading → streaming → idle
|
|
20
|
-
* -
|
|
21
|
+
* - Keeps the settled call's state until the action is called again.
|
|
21
22
|
* - If the same action fires several times, reports the latest call to
|
|
22
23
|
* start. An earlier call that settles later changes nothing it reports;
|
|
23
24
|
* a latest call that was aborted reports idle with nothing. One call at a
|
|
@@ -39,6 +39,7 @@ export declare function useHandle<T, A, S>(handle: Handle<T, A>, selector: (data
|
|
|
39
39
|
* location commit with their page.
|
|
40
40
|
*
|
|
41
41
|
* A value shallow-equal to the last one sets nothing, so a reader renders only
|
|
42
|
-
* when its value moves.
|
|
42
|
+
* when its value moves. A release is compared with what React committed, as in
|
|
43
|
+
* useRouteState.
|
|
43
44
|
*/
|
|
44
45
|
export declare function useCommitAnchoredState<T>(init: () => T, waitForRelease?: boolean): [T, (value: T, signal?: RouteStateSignal) => void];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { RouteStateSignal } from "../event-controller.js";
|
|
2
|
+
/**
|
|
3
|
+
* The value a reader rendered in React's last commit of it, written by its
|
|
4
|
+
* layout effect. A page's release runs in the provider's layout effect, after
|
|
5
|
+
* every reader's (children first), so it reads the commit that brings the
|
|
6
|
+
* page.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCommitted<T>(value: T): {
|
|
9
|
+
readonly current: T;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Sets a route-state reader's value. `next` maps the value React ends on once
|
|
13
|
+
* every set so far commits (`latest`) to the reader's value; `rebase` sets
|
|
14
|
+
* `next` itself, so React recomputes it on whatever base it renders. The value
|
|
15
|
+
* must not be a function.
|
|
16
|
+
*/
|
|
17
|
+
export type RouteStateSetter<T> = (next: (base: T) => T, signal?: RouteStateSignal, rebase?: boolean) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Route state a reader sets as the router store notifies it, in the lane of
|
|
20
|
+
* the notification that carries it. A notification equal to `latest` sets
|
|
21
|
+
* nothing, so a reader renders only when its value moves.
|
|
22
|
+
*
|
|
23
|
+
* A release is compared with what React committed, not with `latest`: while
|
|
24
|
+
* React holds a page, its set is not on screen, and an urgent page that ends
|
|
25
|
+
* the hold brings an equal value. A release that finds every set committed
|
|
26
|
+
* with its value sets nothing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function useRouteState<T>(init: () => T, same: (a: T, b: T) => boolean): [T, RouteStateSetter<T>];
|
|
29
|
+
/** The route a URL hook reads. */
|
|
30
|
+
export interface UrlRoute {
|
|
31
|
+
location: URL;
|
|
32
|
+
params: Record<string, string>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A URL hook's value (usePathname, useParams, useSearchParams): `read` of the
|
|
36
|
+
* route, seeded from the hydration snapshot while the document hydrates, then
|
|
37
|
+
* set as the store notifies it and at a page's release (useRouteState). The
|
|
38
|
+
* release rides the handle channel. `read` applies when the store changes,
|
|
39
|
+
* never in a later render: a new one takes effect from the next change.
|
|
40
|
+
*
|
|
41
|
+
* A read equal to the value it is set over keeps that value, so an object
|
|
42
|
+
* reader changes identity once per value: a release that ends a hold sets the
|
|
43
|
+
* held page's object, which React's render of the held lane keeps.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useUrlValue<T>(read: (route: UrlRoute) => T, same: (a: T, b: T) => boolean): T;
|
|
@@ -231,7 +231,11 @@ export type ActionLifecycleState = "idle" | "loading" | "streaming";
|
|
|
231
231
|
* @internal This type is an implementation detail and may change without notice.
|
|
232
232
|
*/
|
|
233
233
|
export interface TrackedActionState {
|
|
234
|
-
/**
|
|
234
|
+
/**
|
|
235
|
+
* Current lifecycle state of the action. Once the call settles it is
|
|
236
|
+
* "idle" and the rest of the call's state is kept until the action's next
|
|
237
|
+
* call.
|
|
238
|
+
*/
|
|
235
239
|
state: ActionLifecycleState;
|
|
236
240
|
/** Server action function ID (e.g., "addToCart") */
|
|
237
241
|
actionId: string | null;
|
|
@@ -239,12 +243,12 @@ export interface TrackedActionState {
|
|
|
239
243
|
payload: unknown[] | FormData | null;
|
|
240
244
|
/** Error if action failed */
|
|
241
245
|
error: unknown | null;
|
|
242
|
-
/** Result data from the action
|
|
246
|
+
/** Result data from the action */
|
|
243
247
|
result: unknown | null;
|
|
244
248
|
/**
|
|
245
249
|
* The error of a loader that threw while it re-ran after this successful
|
|
246
|
-
* action (the first, when several did). The loader also throws at its
|
|
247
|
-
*
|
|
250
|
+
* action (the first, when several did). The loader also throws at its useLoader read, where the nearest
|
|
251
|
+
* error boundary catches it.
|
|
248
252
|
*/
|
|
249
253
|
revalidationError: unknown | null;
|
|
250
254
|
}
|
|
@@ -68,6 +68,19 @@ export interface BoundaryAudit {
|
|
|
68
68
|
/** The fallback's effect was cleaned up in this task (auditFallback). */
|
|
69
69
|
fallbackGone: boolean;
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* One loaded copy of this module. A test that re-imports the module after
|
|
73
|
+
* vi.resetModules() runs two, and the one its static imports use is not the
|
|
74
|
+
* one on `__rangoSuspenseAudit`. The router's unit-test lock resets and
|
|
75
|
+
* checks each (src/__tests__/kit/suspense-audit-lock.ts).
|
|
76
|
+
*/
|
|
77
|
+
export interface SuspenseAuditInstance {
|
|
78
|
+
/** The violation counters above zero and the last events, if any. */
|
|
79
|
+
violations(): string | undefined;
|
|
80
|
+
forget(): void;
|
|
81
|
+
/** Resolves once the judgments queued so far have run. */
|
|
82
|
+
settle(): Promise<void>;
|
|
83
|
+
}
|
|
71
84
|
export declare function createBoundaryAudit(boundary: string, segmentId: string): BoundaryAudit;
|
|
72
85
|
/**
|
|
73
86
|
* Render phase: the value this render hands the boundary.
|
|
@@ -153,5 +166,10 @@ export declare function auditTreeCause(cause: TreeUpdateCause): void;
|
|
|
153
166
|
* readers subscribe to, or through a pending promise read with use().
|
|
154
167
|
*/
|
|
155
168
|
export declare function auditTreeUpdate(root?: unknown): void;
|
|
156
|
-
/**
|
|
169
|
+
/**
|
|
170
|
+
* Forget every tree, mount, hand-over and count seen so far: the root that
|
|
171
|
+
* held them is gone. A test unmounts its root, production never does
|
|
172
|
+
* (testing/render-route.tsx, src/__tests__/kit/suspense-audit-lock.ts).
|
|
173
|
+
* Creates no report: with the audit off there is none.
|
|
174
|
+
*/
|
|
157
175
|
export declare function forgetSuspenseAudit(): void;
|
|
@@ -385,15 +385,15 @@ export interface TestRouterHandle {
|
|
|
385
385
|
* await act(async () => tail.resolve());
|
|
386
386
|
* // useNavigation(): idle, isStreaming false
|
|
387
387
|
*
|
|
388
|
-
* A navigation started while React holds a page
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* and React renders no later update of the same priority.
|
|
388
|
+
* A navigation started while React holds a page shows its page once the
|
|
389
|
+
* call resolves, with or without act(). A `<Link>` click over a held page
|
|
390
|
+
* still goes inside `await act(async () => ...)` (docs/testing.md).
|
|
392
391
|
*
|
|
393
392
|
* @example
|
|
394
|
-
* await
|
|
395
|
-
*
|
|
396
|
-
* });
|
|
393
|
+
* await router.navigate("/products/2", { loaders: [[ProductLoader, next]] });
|
|
394
|
+
* // React holds /products/2
|
|
395
|
+
* await router.navigate("/products/3", { transition: false });
|
|
396
|
+
* // /products/3 is on screen
|
|
397
397
|
*/
|
|
398
398
|
navigate(url: string, options?: Pick<RenderRouteOptions, "loaders" | "handles"> & Pick<NavigateOptions, "state" | "replace" | "transition"> & {
|
|
399
399
|
streamUntil?: Promise<unknown>;
|
|
@@ -194,22 +194,26 @@ export declare function isSourceMap(fileName: string): boolean;
|
|
|
194
194
|
* hashed by the routers that reach it (resolveRouterMembers), so nothing the
|
|
195
195
|
* map says is lost by skipping it.
|
|
196
196
|
*
|
|
197
|
-
* Works on the
|
|
198
|
-
* keeps the map in every router's hash: more
|
|
197
|
+
* Works on the module markers, so a minified server build (which has none),
|
|
198
|
+
* or a map no marker follows, keeps the map in every router's hash: more
|
|
199
|
+
* clearing, never less.
|
|
199
200
|
*/
|
|
200
201
|
export declare function stripServerReferenceMap(source: string): string;
|
|
201
202
|
/**
|
|
202
|
-
* Take the module paths out of a chunk's
|
|
203
|
+
* Take the module paths out of a chunk's module markers.
|
|
203
204
|
*
|
|
204
|
-
* The
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
205
|
+
* The path says where the build ran, not what it built: it is relative to the
|
|
206
|
+
* directory `vite build` was started from (`vite build apps/web` from a
|
|
207
|
+
* repository root prints other paths than `vite build` in the app), it holds
|
|
208
|
+
* the pnpm store directory with its peer suffix, and a virtual id is printed
|
|
209
|
+
* verbatim, absolute paths in its query included. The code after the marker
|
|
210
|
+
* is hashed either way.
|
|
211
|
+
*
|
|
212
|
+
* A `//#region` line is always a marker. A `// ` line is one only when it
|
|
213
|
+
* names a module of the chunk (`moduleIds`): a kept comment or a line of a
|
|
214
|
+
* multi-line string can start the same way, and is hashed.
|
|
211
215
|
*/
|
|
212
|
-
export declare function
|
|
216
|
+
export declare function stripModulePaths(source: string, moduleIds: readonly string[]): string;
|
|
213
217
|
/** One thing a version is a hash of: its name and the digest of its bytes. */
|
|
214
218
|
export type VersionInput = readonly [name: string, digest: string];
|
|
215
219
|
/** One bundle file, digested once for every router. */
|
|
@@ -237,8 +241,8 @@ export interface DigestedFile {
|
|
|
237
241
|
*
|
|
238
242
|
* Three things are taken out of a chunk's text first, each because it says
|
|
239
243
|
* where or how the build ran: the server-reference map's body
|
|
240
|
-
* ({@link stripServerReferenceMap}), the paths in
|
|
241
|
-
* ({@link
|
|
244
|
+
* ({@link stripServerReferenceMap}), the paths in module markers
|
|
245
|
+
* ({@link stripModulePaths}), and the hashed names of bundle files. A name
|
|
242
246
|
* carries the content hash of its file, and every chunk importing the file
|
|
243
247
|
* has the name in its bytes, so one router's change would otherwise move the
|
|
244
248
|
* digest of every chunk naming its chunk. Only names with a content hash are
|
|
@@ -41,7 +41,7 @@ export declare function canonicalAssetsManifestBinding(code: string): string | u
|
|
|
41
41
|
* (`ServerReferencesManager.claimMap`), which varies with the concurrent
|
|
42
42
|
* scan builds (e2e/test-app: 2 of 2 consecutive builds differed). Sorted
|
|
43
43
|
* here so a minified server build, where stripServerReferenceMap finds no
|
|
44
|
-
*
|
|
44
|
+
* module markers, still hashes the same bytes.
|
|
45
45
|
* 2. Local name of the assets-manifest import. plugin-rsc imports the manifest
|
|
46
46
|
* under three names; the bundler merges them into one import per chunk and
|
|
47
47
|
* keeps a different one from build to build (the cache-versions fixture:
|
package/dist/vite/index.js
CHANGED
|
@@ -4491,13 +4491,13 @@ import {
|
|
|
4491
4491
|
Component as Component3,
|
|
4492
4492
|
createElement as createElement4,
|
|
4493
4493
|
isValidElement as isValidElement2,
|
|
4494
|
-
useContext as
|
|
4494
|
+
useContext as useContext18,
|
|
4495
4495
|
useMemo as useMemo9,
|
|
4496
4496
|
Suspense as Suspense2
|
|
4497
4497
|
} from "react";
|
|
4498
4498
|
|
|
4499
4499
|
// src/browser/react/use-handle.ts
|
|
4500
|
-
import { useContext, useState, useEffect, useRef } from "react";
|
|
4500
|
+
import { useContext as useContext2, useState as useState2, useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
4501
4501
|
|
|
4502
4502
|
// src/missing-id-error.ts
|
|
4503
4503
|
var SELF_FILES = /* @__PURE__ */ new Set([
|
|
@@ -4575,6 +4575,19 @@ var NavigationStoreContext = createContext(null);
|
|
|
4575
4575
|
var LocationStateContext = createContext(void 0);
|
|
4576
4576
|
var HydrationBarrierContext = createContext(0);
|
|
4577
4577
|
|
|
4578
|
+
// src/browser/react/use-route-state.ts
|
|
4579
|
+
import {
|
|
4580
|
+
useContext,
|
|
4581
|
+
useEffect,
|
|
4582
|
+
useLayoutEffect,
|
|
4583
|
+
useRef,
|
|
4584
|
+
useState
|
|
4585
|
+
} from "react";
|
|
4586
|
+
var NO_ROUTE = {
|
|
4587
|
+
location: new URL("/", "http://localhost"),
|
|
4588
|
+
params: Object.freeze({})
|
|
4589
|
+
};
|
|
4590
|
+
|
|
4578
4591
|
// src/handles/meta.ts
|
|
4579
4592
|
function isUnsetDescriptor(descriptor) {
|
|
4580
4593
|
return typeof descriptor === "object" && descriptor !== null && "unset" in descriptor && typeof descriptor.unset === "string";
|
|
@@ -4704,18 +4717,18 @@ function collectMeta(segments) {
|
|
|
4704
4717
|
var Meta = createHandle(collectMeta, "__rsc_router_meta__");
|
|
4705
4718
|
|
|
4706
4719
|
// src/theme/theme-context.ts
|
|
4707
|
-
import { createContext as createContext2, useContext as
|
|
4720
|
+
import { createContext as createContext2, useContext as useContext3 } from "react";
|
|
4708
4721
|
var ThemeContext = createContext2(null);
|
|
4709
4722
|
|
|
4710
4723
|
// src/browser/react/nonce-context.ts
|
|
4711
|
-
import { createContext as createContext3, useContext as
|
|
4724
|
+
import { createContext as createContext3, useContext as useContext4 } from "react";
|
|
4712
4725
|
var NonceContext = createContext3(void 0);
|
|
4713
4726
|
|
|
4714
4727
|
// src/handles/MetaTags.tsx
|
|
4715
4728
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4716
4729
|
|
|
4717
4730
|
// src/handles/Scripts.tsx
|
|
4718
|
-
import { useState as
|
|
4731
|
+
import { useState as useState3 } from "react";
|
|
4719
4732
|
|
|
4720
4733
|
// src/handles/script.ts
|
|
4721
4734
|
function validateConfigDev(config) {
|
|
@@ -4769,7 +4782,7 @@ var Script = createHandle(collectScripts, "__rsc_router_script__");
|
|
|
4769
4782
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4770
4783
|
|
|
4771
4784
|
// src/browser/react/ScrollRestoration.tsx
|
|
4772
|
-
import { useEffect as
|
|
4785
|
+
import { useEffect as useEffect3 } from "react";
|
|
4773
4786
|
|
|
4774
4787
|
// src/browser/scroll-restoration.ts
|
|
4775
4788
|
init_logging();
|
|
@@ -4783,12 +4796,12 @@ import { Component, Suspense, use as use2, useMemo as useMemo3 } from "react";
|
|
|
4783
4796
|
|
|
4784
4797
|
// src/outlet-provider.tsx
|
|
4785
4798
|
import {
|
|
4786
|
-
useContext as
|
|
4799
|
+
useContext as useContext5,
|
|
4787
4800
|
useMemo
|
|
4788
4801
|
} from "react";
|
|
4789
4802
|
|
|
4790
4803
|
// src/suspense-audit-react.tsx
|
|
4791
|
-
import { useEffect as
|
|
4804
|
+
import { useEffect as useEffect4, useLayoutEffect as useLayoutEffect2, useRef as useRef3 } from "react";
|
|
4792
4805
|
|
|
4793
4806
|
// src/suspense-audit.ts
|
|
4794
4807
|
init_internal_debug();
|
|
@@ -4803,13 +4816,13 @@ import { jsx as jsx3 } from "react/jsx-runtime";
|
|
|
4803
4816
|
import { createElement as createElement2 } from "react";
|
|
4804
4817
|
|
|
4805
4818
|
// src/loader-redirect.tsx
|
|
4806
|
-
import { useEffect as
|
|
4819
|
+
import { useEffect as useEffect5 } from "react";
|
|
4807
4820
|
|
|
4808
4821
|
// src/browser/react/use-router.ts
|
|
4809
|
-
import { useContext as
|
|
4822
|
+
import { useContext as useContext7, useMemo as useMemo2 } from "react";
|
|
4810
4823
|
|
|
4811
4824
|
// src/browser/react/use-mount.ts
|
|
4812
|
-
import { useContext as
|
|
4825
|
+
import { useContext as useContext6 } from "react";
|
|
4813
4826
|
|
|
4814
4827
|
// src/browser/react/mount-context.ts
|
|
4815
4828
|
import {
|
|
@@ -5002,12 +5015,12 @@ import {
|
|
|
5002
5015
|
startTransition,
|
|
5003
5016
|
use as use3,
|
|
5004
5017
|
useCallback,
|
|
5005
|
-
useContext as
|
|
5006
|
-
useEffect as
|
|
5018
|
+
useContext as useContext8,
|
|
5019
|
+
useEffect as useEffect6,
|
|
5007
5020
|
useMemo as useMemo4,
|
|
5008
5021
|
useOptimistic,
|
|
5009
|
-
useRef as
|
|
5010
|
-
useState as
|
|
5022
|
+
useRef as useRef4,
|
|
5023
|
+
useState as useState4
|
|
5011
5024
|
} from "react";
|
|
5012
5025
|
|
|
5013
5026
|
// src/loader-store.ts
|
|
@@ -5169,37 +5182,23 @@ function insertSegments(node, segments, index, leafBase, paramNames) {
|
|
|
5169
5182
|
}
|
|
5170
5183
|
|
|
5171
5184
|
// src/browser/react/use-navigation.ts
|
|
5172
|
-
import {
|
|
5173
|
-
useContext as useContext8,
|
|
5174
|
-
useState as useState4,
|
|
5175
|
-
useEffect as useEffect6,
|
|
5176
|
-
useLayoutEffect as useLayoutEffect2,
|
|
5177
|
-
useRef as useRef4
|
|
5178
|
-
} from "react";
|
|
5185
|
+
import { useContext as useContext9, useEffect as useEffect7, useRef as useRef5 } from "react";
|
|
5179
5186
|
|
|
5180
5187
|
// src/browser/react/use-pathname.ts
|
|
5181
|
-
import { useContext as
|
|
5188
|
+
import { useContext as useContext10 } from "react";
|
|
5182
5189
|
|
|
5183
5190
|
// src/client-urls/optimistic-location.ts
|
|
5184
5191
|
import { createContext as createContext6 } from "react";
|
|
5185
5192
|
var OptimisticLocationContext = createContext6(null);
|
|
5186
5193
|
|
|
5187
5194
|
// src/browser/react/use-search-params.ts
|
|
5188
|
-
import {
|
|
5189
|
-
useCallback as useCallback2,
|
|
5190
|
-
useContext as useContext10,
|
|
5191
|
-
useEffect as useEffect8,
|
|
5192
|
-
useMemo as useMemo5,
|
|
5193
|
-
useRef as useRef6,
|
|
5194
|
-
useState as useState6
|
|
5195
|
-
} from "react";
|
|
5195
|
+
import { useCallback as useCallback2, useContext as useContext11, useMemo as useMemo5 } from "react";
|
|
5196
5196
|
|
|
5197
5197
|
// src/browser/react/use-params.ts
|
|
5198
|
-
import { useContext as
|
|
5199
|
-
var EMPTY_PARAMS = Object.freeze({});
|
|
5198
|
+
import { useContext as useContext12 } from "react";
|
|
5200
5199
|
|
|
5201
5200
|
// src/browser/react/use-action.ts
|
|
5202
|
-
import { useContext as
|
|
5201
|
+
import { useContext as useContext13, useState as useState5, useEffect as useEffect8, useRef as useRef6 } from "react";
|
|
5203
5202
|
|
|
5204
5203
|
// src/browser/event-controller.ts
|
|
5205
5204
|
init_notify_listeners();
|
|
@@ -5262,31 +5261,31 @@ function subscribeToLocationChange(eventController, listener) {
|
|
|
5262
5261
|
}
|
|
5263
5262
|
|
|
5264
5263
|
// src/browser/react/use-segments.ts
|
|
5265
|
-
import { useContext as
|
|
5264
|
+
import { useContext as useContext14, useEffect as useEffect9, useRef as useRef7 } from "react";
|
|
5266
5265
|
|
|
5267
5266
|
// src/browser/react/NavigationProvider.tsx
|
|
5268
5267
|
import {
|
|
5269
|
-
useState as
|
|
5270
|
-
useEffect as
|
|
5268
|
+
useState as useState8,
|
|
5269
|
+
useEffect as useEffect11,
|
|
5271
5270
|
useLayoutEffect as useLayoutEffect4,
|
|
5272
5271
|
useCallback as useCallback4,
|
|
5273
5272
|
useMemo as useMemo7,
|
|
5274
|
-
useRef as
|
|
5273
|
+
useRef as useRef9,
|
|
5275
5274
|
use as use4,
|
|
5276
5275
|
startTransition as startTransition2
|
|
5277
5276
|
} from "react";
|
|
5278
5277
|
|
|
5279
5278
|
// src/root-error-boundary.tsx
|
|
5280
|
-
import { Component as Component2, useState as
|
|
5279
|
+
import { Component as Component2, useState as useState6 } from "react";
|
|
5281
5280
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
5282
5281
|
|
|
5283
5282
|
// src/theme/ThemeProvider.tsx
|
|
5284
5283
|
import {
|
|
5285
5284
|
useCallback as useCallback3,
|
|
5286
|
-
useEffect as
|
|
5285
|
+
useEffect as useEffect10,
|
|
5287
5286
|
useLayoutEffect as useLayoutEffect3,
|
|
5288
5287
|
useMemo as useMemo6,
|
|
5289
|
-
useState as
|
|
5288
|
+
useState as useState7
|
|
5290
5289
|
} from "react";
|
|
5291
5290
|
|
|
5292
5291
|
// src/theme/constants.ts
|
|
@@ -5320,18 +5319,18 @@ import { jsx as jsx7 } from "react/jsx-runtime";
|
|
|
5320
5319
|
import {
|
|
5321
5320
|
forwardRef,
|
|
5322
5321
|
useCallback as useCallback5,
|
|
5323
|
-
useContext as
|
|
5324
|
-
useEffect as
|
|
5322
|
+
useContext as useContext16,
|
|
5323
|
+
useEffect as useEffect13,
|
|
5325
5324
|
useMemo as useMemo8,
|
|
5326
|
-
useRef as
|
|
5325
|
+
useRef as useRef10
|
|
5327
5326
|
} from "react";
|
|
5328
5327
|
|
|
5329
5328
|
// src/browser/react/use-link-status.ts
|
|
5330
5329
|
import {
|
|
5331
5330
|
createContext as createContext7,
|
|
5332
|
-
useContext as
|
|
5333
|
-
useState as
|
|
5334
|
-
useEffect as
|
|
5331
|
+
useContext as useContext15,
|
|
5332
|
+
useState as useState9,
|
|
5333
|
+
useEffect as useEffect12
|
|
5335
5334
|
} from "react";
|
|
5336
5335
|
var LinkContext = createContext7(
|
|
5337
5336
|
null
|
|
@@ -5532,14 +5531,14 @@ var Link = forwardRef(function Link2({
|
|
|
5532
5531
|
onClick,
|
|
5533
5532
|
...props
|
|
5534
5533
|
}, ref) {
|
|
5535
|
-
const ctx =
|
|
5534
|
+
const ctx = useContext16(NavigationStoreContext);
|
|
5536
5535
|
const isExternal = isExternalUrl(to, ctx?.origin);
|
|
5537
5536
|
const resolvedTo = useMemo8(
|
|
5538
5537
|
() => isExternal ? to : prefixBasename(to, ctx?.basename),
|
|
5539
5538
|
[to, isExternal, ctx?.basename]
|
|
5540
5539
|
);
|
|
5541
5540
|
const configuredStrategy = prefetch ?? ctx?.defaultPrefetch ?? ENVIRONMENT_DEFAULT_PREFETCH;
|
|
5542
|
-
const internalRef =
|
|
5541
|
+
const internalRef = useRef10(null);
|
|
5543
5542
|
const setRef = useCallback5(
|
|
5544
5543
|
(node) => {
|
|
5545
5544
|
internalRef.current = node;
|
|
@@ -5551,7 +5550,7 @@ var Link = forwardRef(function Link2({
|
|
|
5551
5550
|
},
|
|
5552
5551
|
[ref]
|
|
5553
5552
|
);
|
|
5554
|
-
const stateRef =
|
|
5553
|
+
const stateRef = useRef10(state);
|
|
5555
5554
|
stateRef.current = state;
|
|
5556
5555
|
const handleClick = useCallback5(
|
|
5557
5556
|
(e) => {
|
|
@@ -5608,7 +5607,7 @@ var Link = forwardRef(function Link2({
|
|
|
5608
5607
|
);
|
|
5609
5608
|
}
|
|
5610
5609
|
}, [configuredStrategy, resolvedTo, isExternal, ctx, prefetchKey]);
|
|
5611
|
-
|
|
5610
|
+
useEffect13(() => {
|
|
5612
5611
|
if (isExternal || !ctx?.store) return;
|
|
5613
5612
|
if (configuredStrategy !== "viewport" && configuredStrategy !== "render" && configuredStrategy !== "adaptive") {
|
|
5614
5613
|
return;
|
|
@@ -5728,7 +5727,7 @@ var Breadcrumbs = createHandle(
|
|
|
5728
5727
|
);
|
|
5729
5728
|
|
|
5730
5729
|
// src/browser/react/location-state.ts
|
|
5731
|
-
import { useContext as
|
|
5730
|
+
import { useContext as useContext17, useEffect as useEffect14 } from "react";
|
|
5732
5731
|
|
|
5733
5732
|
// src/browser/react/use-href.tsx
|
|
5734
5733
|
import { useCallback as useCallback6 } from "react";
|
|
@@ -5944,7 +5943,7 @@ import {
|
|
|
5944
5943
|
useDeferredValue,
|
|
5945
5944
|
useLayoutEffect as useLayoutEffect5,
|
|
5946
5945
|
useMemo as useMemo10,
|
|
5947
|
-
useState as
|
|
5946
|
+
useState as useState10
|
|
5948
5947
|
} from "react";
|
|
5949
5948
|
|
|
5950
5949
|
// src/client-urls/navigation.ts
|
|
@@ -7142,7 +7141,7 @@ function resolveVersionsFrom(table, routerId2) {
|
|
|
7142
7141
|
// package.json
|
|
7143
7142
|
var package_default = {
|
|
7144
7143
|
name: "@rangojs/router",
|
|
7145
|
-
version: "0.
|
|
7144
|
+
version: "0.30.1",
|
|
7146
7145
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
7147
7146
|
keywords: [
|
|
7148
7147
|
"react",
|
|
@@ -8054,20 +8053,39 @@ var SERVER_CSS_MODULE = /^virtual:vite-rsc\/css\?type=rsc&id=([^&]+)/;
|
|
|
8054
8053
|
function isSourceMap(fileName) {
|
|
8055
8054
|
return fileName.endsWith(".map");
|
|
8056
8055
|
}
|
|
8057
|
-
var
|
|
8058
|
-
|
|
8059
|
-
|
|
8056
|
+
var MODULE_MARKER = /^\/\/(#region)? (.+)$/gm;
|
|
8057
|
+
var SERVER_REFERENCE_MAP = new RegExp(
|
|
8058
|
+
`(^//(?:#region)? ${escapeRegExp(`\\0${SERVER_REFERENCES_MODULE_ID.slice(1)}`)}
|
|
8059
|
+
)[\\s\\S]*?(?=^//(?: |#endregion))`,
|
|
8060
|
+
"m"
|
|
8061
|
+
);
|
|
8060
8062
|
function stripServerReferenceMap(source) {
|
|
8061
|
-
|
|
8062
|
-
if (start === -1) return source;
|
|
8063
|
-
const bodyStart = start + SERVER_REFERENCES_REGION_START.length;
|
|
8064
|
-
const end = source.indexOf(REGION_END, bodyStart);
|
|
8065
|
-
if (end === -1) return source;
|
|
8066
|
-
return source.slice(0, bodyStart) + source.slice(end);
|
|
8063
|
+
return source.replace(SERVER_REFERENCE_MAP, "$1");
|
|
8067
8064
|
}
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8065
|
+
function printedModuleIds(moduleIds) {
|
|
8066
|
+
const printed = /* @__PURE__ */ new Set();
|
|
8067
|
+
for (const id of moduleIds) {
|
|
8068
|
+
if (!isAbsolutePath(id)) {
|
|
8069
|
+
printed.add(id.replaceAll("\0", "\\0"));
|
|
8070
|
+
continue;
|
|
8071
|
+
}
|
|
8072
|
+
const segments = id.replaceAll("\\", "/").split("/");
|
|
8073
|
+
for (let index = 0; index < segments.length; index++) {
|
|
8074
|
+
printed.add(segments.slice(index).join("/"));
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
return printed;
|
|
8078
|
+
}
|
|
8079
|
+
function stripModulePaths(source, moduleIds) {
|
|
8080
|
+
let printed;
|
|
8081
|
+
return source.replace(
|
|
8082
|
+
MODULE_MARKER,
|
|
8083
|
+
(line, region, name) => {
|
|
8084
|
+
if (region) return "//#region";
|
|
8085
|
+
printed ??= printedModuleIds(moduleIds);
|
|
8086
|
+
return printed.has(name.replace(/^(?:\.\.\/)+/, "")) ? "//" : line;
|
|
8087
|
+
}
|
|
8088
|
+
);
|
|
8071
8089
|
}
|
|
8072
8090
|
var FILE_REFERENCE = "\0";
|
|
8073
8091
|
var FOREIGN_FILE = "~";
|
|
@@ -8119,8 +8137,9 @@ function digestBundle(bundle, projectRoot, read, label) {
|
|
|
8119
8137
|
};
|
|
8120
8138
|
}
|
|
8121
8139
|
const references = [];
|
|
8122
|
-
const text =
|
|
8123
|
-
stripServerReferenceMap(decoder3.decode(bytes))
|
|
8140
|
+
const text = stripModulePaths(
|
|
8141
|
+
stripServerReferenceMap(decoder3.decode(bytes)),
|
|
8142
|
+
chunk.moduleIds
|
|
8124
8143
|
);
|
|
8125
8144
|
const blanked = reference ? text.replace(reference, (name) => {
|
|
8126
8145
|
references.push(fileOfBaseName.get(name));
|
package/package.json
CHANGED
|
@@ -450,16 +450,12 @@ function StockPanel() {
|
|
|
450
450
|
}
|
|
451
451
|
|
|
452
452
|
function SaveStock({ sku }: { sku: string }) {
|
|
453
|
+
// Kept until the next save starts.
|
|
453
454
|
const { revalidationError } = useAction(saveStock);
|
|
454
|
-
const [stale, setStale] = useState(false);
|
|
455
|
-
// useAction resets to idle once the action has settled: keep the notice.
|
|
456
|
-
useEffect(() => {
|
|
457
|
-
if (revalidationError) setStale(true);
|
|
458
|
-
}, [revalidationError]);
|
|
459
455
|
return (
|
|
460
456
|
<form action={saveStock.bind(null, sku)}>
|
|
461
457
|
<button>Save</button>
|
|
462
|
-
{
|
|
458
|
+
{revalidationError != null && (
|
|
463
459
|
<p role="status">Saved. The stock count could not be refreshed.</p>
|
|
464
460
|
)}
|
|
465
461
|
</form>
|
|
@@ -196,6 +196,14 @@ Track the lifecycle of a server action, wherever on the page it was invoked.
|
|
|
196
196
|
If the same action fires several times, the hook reports the latest call: the
|
|
197
197
|
last one to start.
|
|
198
198
|
|
|
199
|
+
- Once the call settles, `state` is `idle` and the rest of its state
|
|
200
|
+
(`result`, `error`, `revalidationError`, `payload`, `actionId`) stays until
|
|
201
|
+
the same action is called again: through navigations and Back/Forward, and
|
|
202
|
+
in a component that mounts after the call settled. Every reader of the
|
|
203
|
+
same action (a function or a full id) reads the same call; a string reader
|
|
204
|
+
follows the latest call of any action with that export name. The next
|
|
205
|
+
call reads `loading` with none of them, then its own. A document load
|
|
206
|
+
starts with nothing.
|
|
199
207
|
- When the latest call returns before an earlier one, the hook shows its
|
|
200
208
|
result. The earlier call settling afterwards changes nothing the hook
|
|
201
209
|
reports, a result or an error alike. That call still runs to its end: its
|
|
@@ -203,8 +211,7 @@ last one to start.
|
|
|
203
211
|
page, and an error-boundary response replaces it.
|
|
204
212
|
- A latest call that was aborted reports nothing: `idle`, with no result or
|
|
205
213
|
error. The hook does not fall back to an earlier call. The router aborts
|
|
206
|
-
calls in flight when
|
|
207
|
-
Back/Forward into or out of an intercept.
|
|
214
|
+
the other calls in flight when a call's response is an error boundary.
|
|
208
215
|
- `useNavigation()` stays `loading` while any call runs.
|
|
209
216
|
|
|
210
217
|
Which calls count as the same action depends on what you pass:
|
|
@@ -90,9 +90,9 @@ reads (a selector, the full state): work that starts shows at once
|
|
|
90
90
|
when the response stream ended earlier, and agrees with every other
|
|
91
91
|
`useNavigation()` reader on the screen. A page that ends the hold urgently (a
|
|
92
92
|
Back to a page without `transition()`, a link with `transition={false}`)
|
|
93
|
-
shows with its own values in every `useNavigation()` reader
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
shows with its own values in every `useNavigation()` reader, and with its URL
|
|
94
|
+
in `usePathname()`, `useParams()`, `useSearchParams()` and `useSegments()`,
|
|
95
|
+
also when it is the URL React was holding.
|
|
96
96
|
|
|
97
97
|
The rule holds for readers mounted before the page was handed to React. A
|
|
98
98
|
reader that mounts while the page is held (a menu opened during the wait)
|
package/skills/hooks/urls.md
CHANGED
|
@@ -123,6 +123,7 @@ click or `router.push()`.
|
|
|
123
123
|
| Back/Forward, entry fetched again | when the fetched page commits; until then the page being left is on screen |
|
|
124
124
|
| a Back/Forward whose fetch fails | with the error boundary: they report the entry the browser is on |
|
|
125
125
|
| `router.push(url, { revalidate: false })` | at once: nothing is fetched and the page stays |
|
|
126
|
+
| `transition={false}` over a held page | with that page's first screen, also on the URL React was holding |
|
|
126
127
|
| inside an optimistic `clientUrls()` destination | at the click, for that branch only (see `/client-urls`) |
|
|
127
128
|
|
|
128
129
|
**A newer click that fails while a page is held.** Click a link, and while
|