@octanejs/remix-router 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/package.json +12 -7
- package/src/index.ts +16 -14
- package/src/lib/Await.tsrx +1 -1
- package/src/lib/DefaultErrorComponent.tsrx +3 -3
- package/src/lib/RenderErrorBoundary.tsrx +1 -1
- package/src/lib/actions.ts +1 -1
- package/src/lib/components/MemoryRouter.tsrx +1 -1
- package/src/lib/components/Navigate.ts +1 -1
- package/src/lib/components/Router.tsrx +1 -1
- package/src/lib/components/RouterProvider.tsrx +1 -1
- package/src/lib/components/Routes.tsrx +1 -1
- package/src/lib/components/routes-collector.ts +1 -8
- package/src/lib/components/utils.ts +4 -65
- package/src/lib/components/with-props.ts +1 -1
- package/src/lib/context.ts +2 -4
- package/src/lib/dom/Form.tsrx +1 -1
- package/src/lib/dom/Link.tsrx +1 -1
- package/src/lib/dom/NavLink.tsrx +1 -1
- package/src/lib/dom/dom.ts +1 -1
- package/src/lib/dom/hooks.ts +1 -1
- package/src/lib/dom/lib.ts +8 -7
- package/src/lib/dom/routers.tsrx +1 -1
- package/src/lib/dom/server.tsrx +6 -28
- package/src/lib/errors.ts +1 -1
- package/src/lib/hooks.ts +6 -16
- package/src/lib/href.ts +9 -4
- package/src/lib/router/history.ts +2 -2
- package/src/lib/router/instrumentation.ts +391 -187
- package/src/lib/router/links.ts +1 -1
- package/src/lib/router/router.ts +128 -78
- package/src/lib/router/server-runtime-types.ts +8 -11
- package/src/lib/router/url.ts +1 -1
- package/src/lib/router/utils.ts +107 -31
- package/src/lib/server-runtime/cookies.ts +7 -7
- package/src/lib/server-runtime/crypto.ts +2 -2
- package/src/lib/server-runtime/mode.ts +1 -1
- package/src/lib/server-runtime/sessions/cookieStorage.ts +1 -1
- package/src/lib/server-runtime/sessions/memoryStorage.ts +1 -1
- package/src/lib/server-runtime/sessions.ts +8 -5
- package/src/lib/server-runtime/warnings.ts +1 -1
- package/src/lib/types/future.ts +1 -7
- package/src/lib/types/params.ts +1 -1
- package/src/lib/types/register.ts +1 -1
- package/src/lib/types/route-module.ts +1 -1
- package/src/lib/types/utils.ts +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[react-router](https://reactrouter.com) for the [octane](https://github.com/octanejs/octane) UI framework.
|
|
4
4
|
|
|
5
|
-
react-router
|
|
5
|
+
react-router v8 ships as a single package, so this port **vendors the
|
|
6
6
|
framework-agnostic router core byte-close** (loaders, actions, redirects,
|
|
7
|
-
matching, history — validated by 161
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
matching, history — validated by 161 ported upstream router tests plus four
|
|
8
|
+
focused v8.2 regression pins) and transcribes the React layer onto octane's
|
|
9
|
+
hooks. The shipped runtime surface matches react-router 1:1 — existing code
|
|
10
10
|
works by changing the import.
|
|
11
11
|
|
|
12
12
|
**The port is complete — full export parity.** Data mode, declarative mode
|
|
@@ -59,11 +59,25 @@ function User() @{
|
|
|
59
59
|
| `@octanejs/remix-router` | the vendored core surface (matchPath, redirect, data, …) + `createMemoryRouter`, `RouterProvider`, `Outlet`, `Await`, `Link`, `useLinkClickHandler`, the full read-hook family (`useLoaderData`, `useNavigate`, `useNavigation`, `useRouteError`, …), declarative mode (`MemoryRouter`, `Routes`/`Route`, `Navigate`, `createRoutesFromChildren`/`Elements`), the DOM layer (`createBrowserRouter`/`createHashRouter`, `BrowserRouter`/`HashRouter`/`unstable_HistoryRouter`, `NavLink`, `useSearchParams`), mutations (`Form`, `useSubmit`, `useFormAction`, `useFetcher`/`useFetchers`), guards/scroll (`useBlocker`, `ScrollRestoration`, …), static SSR (`StaticRouter`/`StaticRouterProvider`/`createStaticHandler`/`createStaticRouter`), and cookies/sessions (`createCookie`, `createCookieSessionStorage`, …) | full parity |
|
|
60
60
|
| `@octanejs/remix-router/dom` | `RouterProvider` with octane's `flushSync` wired in | mirror of `react-router/dom` |
|
|
61
61
|
|
|
62
|
+
## React Router 8 migration
|
|
63
|
+
|
|
64
|
+
- React Router 8 no longer publishes a `react-router-dom` package. Import
|
|
65
|
+
everything from `@octanejs/remix-router`, except the flushSync-enabled
|
|
66
|
+
`RouterProvider`, which comes from `@octanejs/remix-router/dom`.
|
|
67
|
+
- Middleware is always enabled. Loader, action, and middleware `context` is a
|
|
68
|
+
`RouterContextProvider`; the `future.v8_middleware`,
|
|
69
|
+
`future.v8_passThroughRequests`, and
|
|
70
|
+
`future.v8_trailingSlashAwareDataRequests` flags are gone.
|
|
71
|
+
- The internal `hasErrorBoundary` route property is gone. Use `ErrorBoundary`
|
|
72
|
+
or `errorElement`.
|
|
73
|
+
- The package follows Octane's repository-wide Node.js 22 or newer runtime
|
|
74
|
+
contract.
|
|
75
|
+
|
|
62
76
|
## How it works
|
|
63
77
|
|
|
64
78
|
- The router core under `src/lib/router/` is vendored verbatim from
|
|
65
|
-
react-router
|
|
66
|
-
|
|
79
|
+
react-router 8.2.0 (`scripts/vendor-remix-router.mjs`; two documented
|
|
80
|
+
Octane integration deviations; hand-edits prohibited).
|
|
67
81
|
- `RouterProvider` preserves upstream's exact commit paths — `startTransition`
|
|
68
82
|
wrapping, the `flushSync` option, and the ViewTransition dance (dormant until
|
|
69
83
|
Phase E) — on octane's `useState`/`useLayoutEffect`/`useOptimistic`/
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/remix-router",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
6
9
|
"octane": {
|
|
7
10
|
"hookSlots": {
|
|
8
11
|
"manual": [
|
|
@@ -10,7 +13,7 @@
|
|
|
10
13
|
]
|
|
11
14
|
}
|
|
12
15
|
},
|
|
13
|
-
"description": "react-router for the octane renderer — the framework-agnostic router core vendored byte-close from react-router
|
|
16
|
+
"description": "react-router for the octane renderer — the framework-agnostic router core vendored byte-close from react-router v8, with the React layer (RouterProvider, hooks, Link, boundaries) transcribed onto octane.",
|
|
14
17
|
"author": {
|
|
15
18
|
"name": "Dominic Gannaway",
|
|
16
19
|
"email": "dg@domgan.com"
|
|
@@ -35,17 +38,19 @@
|
|
|
35
38
|
"./dom": "./src/dom.ts"
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
38
|
-
"cookie": "^1.
|
|
39
|
-
|
|
41
|
+
"cookie-es": "^3.1.1"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"octane": "0.1.6"
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
47
|
"@tsrx/react": "^0.2.37",
|
|
43
48
|
"esbuild": "^0.28.1",
|
|
44
49
|
"react": "^19.2.0",
|
|
45
50
|
"react-dom": "^19.2.0",
|
|
46
|
-
"react-router": "
|
|
47
|
-
"
|
|
48
|
-
"
|
|
51
|
+
"react-router": "8.2.0",
|
|
52
|
+
"vitest": "^4.1.9",
|
|
53
|
+
"octane": "0.1.6"
|
|
49
54
|
},
|
|
50
55
|
"scripts": {
|
|
51
56
|
"test": "vitest run"
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @octanejs/remix-router — react-router for the octane renderer.
|
|
2
2
|
//
|
|
3
|
-
// react-router
|
|
3
|
+
// react-router v8 ships as a single package whose framework-agnostic core has
|
|
4
4
|
// no runtime subpath, so the core (lib/router/* + framework-free lib helpers)
|
|
5
5
|
// is VENDORED byte-close (see scripts/vendor-remix-router.mjs) and only the
|
|
6
6
|
// React layer is transcribed onto octane's hooks. This entry mirrors upstream
|
|
@@ -24,8 +24,15 @@ export type {
|
|
|
24
24
|
InstrumentRouterFunction,
|
|
25
25
|
InstrumentRouteFunction,
|
|
26
26
|
InstrumentationHandlerResult,
|
|
27
|
+
InstrumentationClientRouterResult,
|
|
28
|
+
InstrumentationServerHandlerResult,
|
|
27
29
|
} from './lib/router/instrumentation';
|
|
28
|
-
export {
|
|
30
|
+
export {
|
|
31
|
+
createStaticHandler,
|
|
32
|
+
IDLE_NAVIGATION,
|
|
33
|
+
IDLE_FETCHER,
|
|
34
|
+
IDLE_BLOCKER,
|
|
35
|
+
} from './lib/router/router';
|
|
29
36
|
export {
|
|
30
37
|
data,
|
|
31
38
|
generatePath,
|
|
@@ -179,12 +186,7 @@ export type {
|
|
|
179
186
|
FetcherWithComponents,
|
|
180
187
|
} from './lib/dom/lib';
|
|
181
188
|
export { Form } from './lib/dom/Form.tsrx';
|
|
182
|
-
export {
|
|
183
|
-
StaticRouter,
|
|
184
|
-
StaticRouterProvider,
|
|
185
|
-
createStaticHandler,
|
|
186
|
-
createStaticRouter,
|
|
187
|
-
} from './lib/dom/server.tsrx';
|
|
189
|
+
export { StaticRouter, StaticRouterProvider, createStaticRouter } from './lib/dom/server.tsrx';
|
|
188
190
|
|
|
189
191
|
// ── UNSAFE_ surface (shipped subset) ────────────────────────────────────────
|
|
190
192
|
export {
|
|
@@ -194,7 +196,10 @@ export {
|
|
|
194
196
|
invariant as UNSAFE_invariant,
|
|
195
197
|
} from './lib/router/history';
|
|
196
198
|
export { createRouter as UNSAFE_createRouter } from './lib/router/router';
|
|
197
|
-
export {
|
|
199
|
+
export {
|
|
200
|
+
defaultMapRouteProperties as UNSAFE_defaultMapRouteProperties,
|
|
201
|
+
ErrorResponseImpl as UNSAFE_ErrorResponseImpl,
|
|
202
|
+
} from './lib/router/utils';
|
|
198
203
|
export {
|
|
199
204
|
DataRouterContext as UNSAFE_DataRouterContext,
|
|
200
205
|
DataRouterStateContext as UNSAFE_DataRouterStateContext,
|
|
@@ -204,10 +209,7 @@ export {
|
|
|
204
209
|
RouteContext as UNSAFE_RouteContext,
|
|
205
210
|
ViewTransitionContext as UNSAFE_ViewTransitionContext,
|
|
206
211
|
} from './lib/context';
|
|
207
|
-
export {
|
|
208
|
-
hydrationRouteProperties as UNSAFE_hydrationRouteProperties,
|
|
209
|
-
mapRouteProperties as UNSAFE_mapRouteProperties,
|
|
210
|
-
} from './lib/components/utils';
|
|
212
|
+
export { hydrationRouteProperties as UNSAFE_hydrationRouteProperties } from './lib/components/utils';
|
|
211
213
|
export {
|
|
212
214
|
WithComponentProps as UNSAFE_WithComponentProps,
|
|
213
215
|
withComponentProps as UNSAFE_withComponentProps,
|
|
@@ -217,7 +219,7 @@ export {
|
|
|
217
219
|
withErrorBoundaryProps as UNSAFE_withErrorBoundaryProps,
|
|
218
220
|
} from './lib/components/with-props';
|
|
219
221
|
export type { Register } from './lib/types/register';
|
|
220
|
-
export type {
|
|
222
|
+
export type { Future } from './lib/types/future';
|
|
221
223
|
|
|
222
224
|
// ── Server runtime (vendored cookie/session surface) ────────────────────────
|
|
223
225
|
export { createCookie, isCookie } from './lib/server-runtime/cookies';
|
package/src/lib/Await.tsrx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Await — port of react-router@
|
|
1
|
+
// Await — port of react-router@8.2.0 lib/components.tsx's Await +
|
|
2
2
|
// AwaitErrorBoundary + ResolveAwait onto octane. The class boundary becomes an
|
|
3
3
|
// octane @try/@catch; the "throw to the suspense boundary" becomes use(promise)
|
|
4
4
|
// (octane's suspend primitive); the TrackedPromise decoration (_tracked/_data/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// DefaultErrorComponent — port of react-router@
|
|
1
|
+
// DefaultErrorComponent — port of react-router@8.2.0 lib/hooks.tsx's default
|
|
2
2
|
// error UI. Markup-identical (differential fixtures still avoid it — the dev
|
|
3
3
|
// stack trace can never byte-match across runtimes).
|
|
4
4
|
import { useContext } from 'octane';
|
|
5
|
-
import { RouteErrorContext
|
|
6
|
-
import { isRouteErrorResponse } from './router/utils.ts';
|
|
5
|
+
import { RouteErrorContext } from './context.ts';
|
|
6
|
+
import { ENABLE_DEV_WARNINGS, isRouteErrorResponse } from './router/utils.ts';
|
|
7
7
|
|
|
8
8
|
export function DefaultErrorComponent() @{
|
|
9
9
|
const error = useContext(RouteErrorContext);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// RenderErrorBoundary — port of the class boundary in react-router@
|
|
1
|
+
// RenderErrorBoundary — port of the class boundary in react-router@8.2.0
|
|
2
2
|
// lib/hooks.tsx onto octane's @try/@catch (octane has no class components).
|
|
3
3
|
// RSC digest branches are dropped (RSCRouterContext is hardwired false here).
|
|
4
4
|
//
|
package/src/lib/actions.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Vendored from react-router@
|
|
1
|
+
// Vendored from react-router@8.2.0 packages/react-router/lib/actions.ts — unmodified.
|
|
2
2
|
// Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
|
|
3
3
|
export function throwIfPotentialCSRFAttack(
|
|
4
4
|
request: Request,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// MemoryRouter — transcribed from react-router@
|
|
1
|
+
// MemoryRouter — transcribed from react-router@8.2.0 lib/components.tsx.
|
|
2
2
|
// A declarative Router over an in-memory history stack.
|
|
3
3
|
import { startTransition, useCallback, useLayoutEffect, useRef, useState } from 'octane';
|
|
4
4
|
import { createMemoryHistory } from '../router/history.ts';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Navigate — transcribed from react-router@
|
|
1
|
+
// Navigate — transcribed from react-router@8.2.0 lib/components.tsx.
|
|
2
2
|
// Renders nothing; navigates from an effect on mount/update. Plain .ts (no
|
|
3
3
|
// JSX needed); the hooks it composes handle a slotless caller via bare-tag
|
|
4
4
|
// sub-slots.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Router — transcribed from react-router@
|
|
1
|
+
// Router — transcribed from react-router@8.2.0 lib/components.tsx. The
|
|
2
2
|
// low-level context provider every router variant renders through.
|
|
3
3
|
import { useMemo } from 'octane';
|
|
4
4
|
import { LocationContext, NavigationContext } from '../context.ts';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// RouterProvider + DataRoutes + Outlet — transcribed from react-router@
|
|
1
|
+
// RouterProvider + DataRoutes + Outlet — transcribed from react-router@8.2.0
|
|
2
2
|
// lib/components.tsx onto octane. Structure preserved verbatim: useState for
|
|
3
3
|
// router state + layout-effect subscription (early enough for render-driven
|
|
4
4
|
// redirects; subscribe() replays a pre-attach notification), useOptimistic for
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Routes — transcribed from react-router@
|
|
1
|
+
// Routes — transcribed from react-router@8.2.0 lib/components.tsx, hybrid
|
|
2
2
|
// per docs/remix-router-port-plan.md §2a:
|
|
3
3
|
// - descriptor children (createRoutesFromElements results, `{expr}` arrays,
|
|
4
4
|
// prop-position elements) go through createRoutesFromChildren verbatim;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Declarative `<Routes>`/`<Route>` support — transcribed from
|
|
2
|
-
// react-router@
|
|
2
|
+
// react-router@8.2.0 lib/components.tsx with ONE octane-specific mechanism.
|
|
3
3
|
//
|
|
4
4
|
// Upstream walks React children (`createRoutesFromChildren`) reading
|
|
5
5
|
// `element.type === Route`. Octane value-position JSX (argument position, prop
|
|
@@ -60,7 +60,6 @@ const ROUTE_PROP_KEYS = [
|
|
|
60
60
|
'HydrateFallback',
|
|
61
61
|
'errorElement',
|
|
62
62
|
'ErrorBoundary',
|
|
63
|
-
'hasErrorBoundary',
|
|
64
63
|
'shouldRevalidate',
|
|
65
64
|
'handle',
|
|
66
65
|
'lazy',
|
|
@@ -170,8 +169,6 @@ function buildRoute(entry: CollectorEntry, treePath: number[]): RouteObject {
|
|
|
170
169
|
HydrateFallback: p.HydrateFallback,
|
|
171
170
|
errorElement: p.errorElement,
|
|
172
171
|
ErrorBoundary: p.ErrorBoundary,
|
|
173
|
-
hasErrorBoundary:
|
|
174
|
-
p.hasErrorBoundary === true || p.ErrorBoundary != null || p.errorElement != null,
|
|
175
172
|
shouldRevalidate: p.shouldRevalidate,
|
|
176
173
|
handle: p.handle,
|
|
177
174
|
lazy: p.lazy,
|
|
@@ -295,10 +292,6 @@ export function createRoutesFromChildren(
|
|
|
295
292
|
HydrateFallback: element.props.HydrateFallback,
|
|
296
293
|
errorElement: element.props.errorElement,
|
|
297
294
|
ErrorBoundary: element.props.ErrorBoundary,
|
|
298
|
-
hasErrorBoundary:
|
|
299
|
-
element.props.hasErrorBoundary === true ||
|
|
300
|
-
element.props.ErrorBoundary != null ||
|
|
301
|
-
element.props.errorElement != null,
|
|
302
295
|
shouldRevalidate: element.props.shouldRevalidate,
|
|
303
296
|
handle: element.props.handle,
|
|
304
297
|
lazy: element.props.lazy,
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
// Transcribed from react-router@
|
|
2
|
-
// utilities) onto octane:
|
|
1
|
+
// Transcribed from react-router@8.2.0 lib/components.tsx (the non-component
|
|
2
|
+
// utilities) onto octane: hydrationRouteProperties /
|
|
3
3
|
// createMemoryRouter / Deferred / getOptimisticRouterState, plus warnOnce
|
|
4
4
|
// (upstream imports it from lib/server-runtime/warnings.ts — inlined here,
|
|
5
5
|
// the server runtime is out of scope).
|
|
6
|
-
import { createElement } from 'octane';
|
|
7
6
|
import type { InitialEntry } from '../router/history';
|
|
8
7
|
import { createMemoryHistory } from '../router/history';
|
|
9
|
-
import { warning } from '../router/history';
|
|
10
8
|
import type { Router as DataRouter, RouterState } from '../router/router';
|
|
11
9
|
import { createRouter } from '../router/router';
|
|
12
10
|
import type { RouteMatch, RouteObject } from '../router/utils';
|
|
13
|
-
import {
|
|
11
|
+
import { defaultMapRouteProperties } from '../router/utils';
|
|
14
12
|
import { _renderMatches } from '../hooks';
|
|
15
13
|
|
|
16
14
|
/**
|
|
@@ -29,65 +27,6 @@ export function warnOnce(condition: boolean, message: string): void {
|
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
export function mapRouteProperties(route: RouteObject) {
|
|
33
|
-
let updates: Partial<RouteObject> & { hasErrorBoundary: boolean } = {
|
|
34
|
-
// Note: this check also occurs in createRoutesFromChildren so update
|
|
35
|
-
// there if you change this -- please and thank you!
|
|
36
|
-
hasErrorBoundary:
|
|
37
|
-
route.hasErrorBoundary || route.ErrorBoundary != null || route.errorElement != null,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
if (route.Component) {
|
|
41
|
-
if (ENABLE_DEV_WARNINGS) {
|
|
42
|
-
if (route.element) {
|
|
43
|
-
warning(
|
|
44
|
-
false,
|
|
45
|
-
'You should not include both `Component` and `element` on your route - ' +
|
|
46
|
-
'`Component` will be used.',
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
Object.assign(updates, {
|
|
51
|
-
element: createElement(route.Component as any),
|
|
52
|
-
Component: undefined,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (route.HydrateFallback) {
|
|
57
|
-
if (ENABLE_DEV_WARNINGS) {
|
|
58
|
-
if (route.hydrateFallbackElement) {
|
|
59
|
-
warning(
|
|
60
|
-
false,
|
|
61
|
-
'You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - ' +
|
|
62
|
-
'`HydrateFallback` will be used.',
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
Object.assign(updates, {
|
|
67
|
-
hydrateFallbackElement: createElement(route.HydrateFallback as any),
|
|
68
|
-
HydrateFallback: undefined,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (route.ErrorBoundary) {
|
|
73
|
-
if (ENABLE_DEV_WARNINGS) {
|
|
74
|
-
if (route.errorElement) {
|
|
75
|
-
warning(
|
|
76
|
-
false,
|
|
77
|
-
'You should not include both `ErrorBoundary` and `errorElement` on your route - ' +
|
|
78
|
-
'`ErrorBoundary` will be used.',
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
Object.assign(updates, {
|
|
83
|
-
errorElement: createElement(route.ErrorBoundary as any),
|
|
84
|
-
ErrorBoundary: undefined,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return updates;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
30
|
export const hydrationRouteProperties: (keyof RouteObject)[] = [
|
|
92
31
|
'HydrateFallback',
|
|
93
32
|
'hydrateFallbackElement',
|
|
@@ -117,7 +56,7 @@ export function createMemoryRouter(routes: RouteObject[], opts?: MemoryRouterOpt
|
|
|
117
56
|
hydrationData: opts?.hydrationData,
|
|
118
57
|
routes,
|
|
119
58
|
hydrationRouteProperties,
|
|
120
|
-
mapRouteProperties,
|
|
59
|
+
mapRouteProperties: defaultMapRouteProperties,
|
|
121
60
|
dataStrategy: opts?.dataStrategy,
|
|
122
61
|
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
|
|
123
62
|
instrumentations: opts?.instrumentations,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// UNSAFE_With*Props wrappers — transcribed from react-router@
|
|
1
|
+
// UNSAFE_With*Props wrappers — transcribed from react-router@8.2.0
|
|
2
2
|
// lib/components.tsx. Used by framework-mode codegen upstream; exported here
|
|
3
3
|
// for surface parity. Plain .ts: cloneElement/createElement over descriptors.
|
|
4
4
|
import { cloneElement, createElement } from 'octane';
|
package/src/lib/context.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Transcribed from react-router@
|
|
1
|
+
// Transcribed from react-router@8.2.0 lib/context.ts onto octane. The ten
|
|
2
2
|
// contexts and their shapes are verbatim; octane substitutions: createContext/
|
|
3
3
|
// createElement from 'octane', `__DEV__` → NODE_ENV, no displayName (octane
|
|
4
4
|
// contexts carry none). RSCRouterContext is kept (hardwired default false — no
|
|
@@ -48,7 +48,7 @@ export const ViewTransitionContext = createContext<ViewTransitionContextObject>(
|
|
|
48
48
|
isTransitioning: false,
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
// TODO: (
|
|
51
|
+
// TODO: (v9) Change the useFetcher data from `any` to `unknown`
|
|
52
52
|
export type FetchersContextObject = Map<string, any>;
|
|
53
53
|
|
|
54
54
|
export const FetchersContext = createContext<FetchersContextObject>(new Map());
|
|
@@ -125,5 +125,3 @@ export const RouteContext = createContext<RouteContextObject>({
|
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
export const RouteErrorContext = createContext<any>(null);
|
|
128
|
-
|
|
129
|
-
export const ENABLE_DEV_WARNINGS = process.env.NODE_ENV !== 'production';
|
package/src/lib/dom/Form.tsrx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Form — transcribed from react-router@
|
|
1
|
+
// Form — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
|
|
2
2
|
// forwardRef → ref-as-prop. The submit handler is a NATIVE delegated `submit`
|
|
3
3
|
// listener (octane has no synthetic events): `event.submitter` is read
|
|
4
4
|
// directly off the native SubmitEvent where React goes through
|
package/src/lib/dom/Link.tsrx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Link — transcribed from react-router@
|
|
1
|
+
// Link — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
|
|
2
2
|
// forwardRef → ref-as-prop (octane refs are props; documented divergence).
|
|
3
3
|
// Framework-mode prefetching (usePrefetchBehavior / PrefetchPageLinks) is
|
|
4
4
|
// inert outside a FrameworkContext upstream and is dropped here — the
|
package/src/lib/dom/NavLink.tsrx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// NavLink — transcribed from react-router@
|
|
1
|
+
// NavLink — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
|
|
2
2
|
// forwardRef → ref-as-prop. Renders <Link> with active/pending-derived
|
|
3
3
|
// className/style/aria-current; `className`, `style`, and `children` accept
|
|
4
4
|
// render props receiving { isActive, isPending, isTransitioning }. Octane
|
package/src/lib/dom/dom.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Vendored from react-router@
|
|
1
|
+
// Vendored from react-router@8.2.0 packages/react-router/lib/dom/dom.ts — unmodified.
|
|
2
2
|
// Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
|
|
3
3
|
import { warning } from '../router/history';
|
|
4
4
|
import type { RelativeRoutingType } from '../router/router';
|
package/src/lib/dom/hooks.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// DOM hooks — transcribed from react-router@
|
|
1
|
+
// DOM hooks — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto
|
|
2
2
|
// octane. This PR ships useLinkClickHandler (Link's engine); the remaining DOM
|
|
3
3
|
// hooks (useSearchParams, useSubmit, useFetcher, …) land in later phases per
|
|
4
4
|
// docs/remix-router-port-plan.md.
|
package/src/lib/dom/lib.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// DOM-mode entry points + hooks — transcribed from react-router@
|
|
1
|
+
// DOM-mode entry points + hooks — transcribed from react-router@8.2.0
|
|
2
2
|
// lib/dom/lib.tsx onto octane: createBrowserRouter / createHashRouter (with
|
|
3
3
|
// upstream's __staticRouterHydrationData parsing + error deserialization),
|
|
4
4
|
// useSearchParams, and useViewTransitionState (needed internally by NavLink;
|
|
@@ -38,11 +38,12 @@ import type { RouteObject } from '../router/utils';
|
|
|
38
38
|
import {
|
|
39
39
|
ErrorResponseImpl,
|
|
40
40
|
SUPPORTED_ERROR_TYPES,
|
|
41
|
+
defaultMapRouteProperties,
|
|
41
42
|
joinPaths,
|
|
42
43
|
matchPath,
|
|
43
44
|
stripBasename,
|
|
44
45
|
} from '../router/utils';
|
|
45
|
-
import { hydrationRouteProperties
|
|
46
|
+
import { hydrationRouteProperties } from '../components/utils';
|
|
46
47
|
import {
|
|
47
48
|
useBlocker,
|
|
48
49
|
useLocation,
|
|
@@ -81,7 +82,7 @@ export function createBrowserRouter(routes: RouteObject[], opts?: DOMRouterOpts)
|
|
|
81
82
|
history: createBrowserHistory({ window: opts?.window }),
|
|
82
83
|
hydrationData: opts?.hydrationData || parseHydrationData(),
|
|
83
84
|
routes,
|
|
84
|
-
mapRouteProperties,
|
|
85
|
+
mapRouteProperties: defaultMapRouteProperties,
|
|
85
86
|
hydrationRouteProperties,
|
|
86
87
|
dataStrategy: opts?.dataStrategy,
|
|
87
88
|
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
|
|
@@ -102,7 +103,7 @@ export function createHashRouter(routes: RouteObject[], opts?: DOMRouterOpts): D
|
|
|
102
103
|
history: createHashHistory({ window: opts?.window }),
|
|
103
104
|
hydrationData: opts?.hydrationData || parseHydrationData(),
|
|
104
105
|
routes,
|
|
105
|
-
mapRouteProperties,
|
|
106
|
+
mapRouteProperties: defaultMapRouteProperties,
|
|
106
107
|
hydrationRouteProperties,
|
|
107
108
|
dataStrategy: opts?.dataStrategy,
|
|
108
109
|
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
|
|
@@ -134,7 +135,7 @@ function deserializeErrors(errors: DataRouter['state']['errors']): DataRouter['s
|
|
|
134
135
|
let serialized: DataRouter['state']['errors'] = {};
|
|
135
136
|
for (let [key, val] of entries) {
|
|
136
137
|
// Hey you! If you change this, please change the corresponding logic in
|
|
137
|
-
// serializeErrors in
|
|
138
|
+
// serializeErrors in lib/dom/server.tsx :)
|
|
138
139
|
if (val && val.__type === 'RouteErrorResponse') {
|
|
139
140
|
serialized[key] = new ErrorResponseImpl(
|
|
140
141
|
val.status,
|
|
@@ -246,7 +247,7 @@ export function useViewTransitionState(to: To, ...args: any[]): boolean {
|
|
|
246
247
|
|
|
247
248
|
invariant(
|
|
248
249
|
vtContext != null,
|
|
249
|
-
"`useViewTransitionState` must be used within `react-router
|
|
250
|
+
"`useViewTransitionState` must be used within `react-router/dom`'s `RouterProvider`. " +
|
|
250
251
|
'Did you accidentally import `RouterProvider` from `react-router`?',
|
|
251
252
|
);
|
|
252
253
|
|
|
@@ -276,7 +277,7 @@ export function useViewTransitionState(to: To, ...args: any[]): boolean {
|
|
|
276
277
|
|
|
277
278
|
// ── Phase D — mutations ─────────────────────────────────────────────────────
|
|
278
279
|
// useSubmit / useFormAction / useFetcher / useFetchers — transcribed from
|
|
279
|
-
// react-router@
|
|
280
|
+
// react-router@8.2.0 lib/dom/lib.tsx. The dom-side data-router guards mirror
|
|
280
281
|
// upstream's local DataRouterHook enum + console errors.
|
|
281
282
|
|
|
282
283
|
enum DataRouterHook {
|
package/src/lib/dom/routers.tsrx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// BrowserRouter / HashRouter / HistoryRouter — transcribed from
|
|
2
|
-
// react-router@
|
|
2
|
+
// react-router@8.2.0 lib/dom/lib.tsx. Declarative routers over browser /
|
|
3
3
|
// hash / caller-provided history (upstream repeats the subscribe body in each;
|
|
4
4
|
// so does this transcription).
|
|
5
5
|
import { startTransition, useCallback, useLayoutEffect, useRef, useState } from 'octane';
|
package/src/lib/dom/server.tsrx
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
// Static SSR — transcribed from react-router@
|
|
1
|
+
// Static SSR — transcribed from react-router@8.2.0 lib/dom/server.tsx onto
|
|
2
2
|
// octane: StaticRouter (a Router that may not navigate), StaticRouterProvider
|
|
3
3
|
// (renders a static data router + the __staticRouterHydrationData script),
|
|
4
|
-
//
|
|
5
|
-
// createStaticRouter (a stateless DataRouter over a StaticHandlerContext).
|
|
4
|
+
// and createStaticRouter (a stateless DataRouter over a StaticHandlerContext).
|
|
6
5
|
// Render through `octane/server` (renderToString / renderToPipeableStream).
|
|
7
6
|
import type { Location, Path, To } from '../router/history.ts';
|
|
8
7
|
import { Action as NavigationType, createPath, invariant, parsePath } from '../router/history.ts';
|
|
9
|
-
import {
|
|
10
|
-
IDLE_BLOCKER,
|
|
11
|
-
IDLE_FETCHER,
|
|
12
|
-
IDLE_NAVIGATION,
|
|
13
|
-
createStaticHandler as routerCreateStaticHandler,
|
|
14
|
-
} from '../router/router.ts';
|
|
8
|
+
import { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION } from '../router/router.ts';
|
|
15
9
|
import { convertRoutesToDataRoutes, isRouteErrorResponse } from '../router/utils.ts';
|
|
16
10
|
import { ABSOLUTE_URL_REGEX } from '../router/url.ts';
|
|
17
11
|
import { Router } from '../components/Router.tsrx';
|
|
18
12
|
import { DataRoutes } from '../components/RouterProvider.tsrx';
|
|
19
|
-
import { mapRouteProperties } from '../components/utils.ts';
|
|
20
13
|
import {
|
|
21
14
|
DataRouterContext,
|
|
22
15
|
DataRouterStateContext,
|
|
@@ -136,7 +129,7 @@ function serializeErrors(errors) {
|
|
|
136
129
|
const serialized = {};
|
|
137
130
|
for (const [key, val] of entries) {
|
|
138
131
|
// Hey you! If you change this, please change the corresponding logic in
|
|
139
|
-
// deserializeErrors in
|
|
132
|
+
// deserializeErrors in lib/dom/lib.tsx :)
|
|
140
133
|
if (isRouteErrorResponse(val)) {
|
|
141
134
|
serialized[key] = { ...val, __type: 'RouteErrorResponse' };
|
|
142
135
|
} else if (val instanceof Error) {
|
|
@@ -190,22 +183,12 @@ function getStatelessNavigator() {
|
|
|
190
183
|
};
|
|
191
184
|
}
|
|
192
185
|
|
|
193
|
-
/**
|
|
194
|
-
* Create a static handler to perform server-side data loading.
|
|
195
|
-
*/
|
|
196
|
-
export function createStaticHandler(routes, opts) {
|
|
197
|
-
return routerCreateStaticHandler(routes, {
|
|
198
|
-
...opts,
|
|
199
|
-
mapRouteProperties,
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
186
|
/**
|
|
204
187
|
* Create a static DataRouter for server-side rendering.
|
|
205
188
|
*/
|
|
206
189
|
export function createStaticRouter(routes, context, opts = {}) {
|
|
207
190
|
const manifest = {};
|
|
208
|
-
const dataRoutes = convertRoutesToDataRoutes(routes,
|
|
191
|
+
const dataRoutes = convertRoutesToDataRoutes(routes, undefined, undefined, manifest);
|
|
209
192
|
|
|
210
193
|
// Because our context matches may be from a set of routes passed to
|
|
211
194
|
// createStaticHandler(), we update them here with our newly created/enhanced
|
|
@@ -226,12 +209,7 @@ export function createStaticRouter(routes, context, opts = {}) {
|
|
|
226
209
|
return context.basename;
|
|
227
210
|
},
|
|
228
211
|
get future() {
|
|
229
|
-
return {
|
|
230
|
-
v8_middleware: false,
|
|
231
|
-
v8_passThroughRequests: false,
|
|
232
|
-
v8_trailingSlashAwareDataRequests: false,
|
|
233
|
-
...opts?.future,
|
|
234
|
-
};
|
|
212
|
+
return { ...opts?.future };
|
|
235
213
|
},
|
|
236
214
|
get state() {
|
|
237
215
|
return {
|
package/src/lib/errors.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Vendored from react-router@
|
|
1
|
+
// Vendored from react-router@8.2.0 packages/react-router/lib/errors.ts — unmodified.
|
|
2
2
|
// Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
|
|
3
3
|
import { isDataWithResponseInit } from './router/router';
|
|
4
4
|
import { ErrorResponseImpl } from './router/utils';
|
package/src/lib/hooks.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Transcribed from react-router@
|
|
1
|
+
// Transcribed from react-router@8.2.0 lib/hooks.tsx onto octane. Upstream
|
|
2
2
|
// logic, comments, and warning strings are verbatim; octane substitutions:
|
|
3
3
|
// hooks from 'octane' with the binding slot idiom (splitSlot/subSlot — this
|
|
4
4
|
// file is NOT compiled, so exported hooks peel the caller's compiler-injected
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
AwaitContext,
|
|
24
24
|
DataRouterContext,
|
|
25
25
|
DataRouterStateContext,
|
|
26
|
-
ENABLE_DEV_WARNINGS,
|
|
27
26
|
LocationContext,
|
|
28
27
|
NavigationContext,
|
|
29
28
|
RouteContext,
|
|
@@ -55,6 +54,7 @@ import type {
|
|
|
55
54
|
import {
|
|
56
55
|
convertRouteMatchToUiMatch,
|
|
57
56
|
decodePath,
|
|
57
|
+
ENABLE_DEV_WARNINGS,
|
|
58
58
|
getResolveToMatches,
|
|
59
59
|
getRoutePattern,
|
|
60
60
|
joinPaths,
|
|
@@ -223,18 +223,6 @@ export interface NavigateFunction {
|
|
|
223
223
|
const navigateEffectWarning =
|
|
224
224
|
`You should call navigate() in a useEffect(), not when ` + `your component is first rendered.`;
|
|
225
225
|
|
|
226
|
-
// Mute warnings for calls to useNavigate in SSR environments
|
|
227
|
-
function useIsomorphicLayoutEffect(cb: Parameters<typeof useLayoutEffect>[0], slot?: symbol) {
|
|
228
|
-
let isStatic = useContext(NavigationContext).static;
|
|
229
|
-
if (!isStatic) {
|
|
230
|
-
// We should be able to get rid of this once react 18.3 is released
|
|
231
|
-
// See: https://github.com/facebook/react/pull/26395
|
|
232
|
-
// OCTANE: conditional hook calls are fine — hooks are slot-keyed, not
|
|
233
|
-
// call-order keyed.
|
|
234
|
-
useLayoutEffect(cb, undefined, subSlot(slot, 'ile'));
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
226
|
/**
|
|
239
227
|
* Returns a function that lets you navigate programmatically in the browser in
|
|
240
228
|
* response to user interactions or effects.
|
|
@@ -406,10 +394,11 @@ function useNavigateUnstable(slot?: symbol): NavigateFunction {
|
|
|
406
394
|
let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
|
|
407
395
|
|
|
408
396
|
let activeRef = useRef(false, subSlot(slot, 'unav:ref'));
|
|
409
|
-
|
|
397
|
+
useLayoutEffect(
|
|
410
398
|
() => {
|
|
411
399
|
activeRef.current = true;
|
|
412
400
|
},
|
|
401
|
+
undefined,
|
|
413
402
|
subSlot(slot, 'unav:ile'),
|
|
414
403
|
);
|
|
415
404
|
|
|
@@ -1628,10 +1617,11 @@ function useNavigateStable(slot?: symbol): NavigateFunction {
|
|
|
1628
1617
|
let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
|
|
1629
1618
|
|
|
1630
1619
|
let activeRef = useRef(false, subSlot(slot, 'snav:ref'));
|
|
1631
|
-
|
|
1620
|
+
useLayoutEffect(
|
|
1632
1621
|
() => {
|
|
1633
1622
|
activeRef.current = true;
|
|
1634
1623
|
},
|
|
1624
|
+
undefined,
|
|
1635
1625
|
subSlot(slot, 'snav:ile'),
|
|
1636
1626
|
);
|
|
1637
1627
|
|