@unitflow/router 0.1.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.
- package/README.md +154 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/public.d.ts +11 -0
- package/dist/public.d.ts.map +1 -0
- package/dist/public.js +21 -0
- package/dist/public.js.map +1 -0
- package/dist/react.d.ts +125 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +150 -0
- package/dist/react.js.map +1 -0
- package/dist/router-group.d.ts +2 -0
- package/dist/router-group.d.ts.map +1 -0
- package/dist/router-group.js +2 -0
- package/dist/router-group.js.map +1 -0
- package/dist/router.d.ts +469 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +870 -0
- package/dist/router.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @unitflow/router
|
|
2
|
+
|
|
3
|
+
Effect-native, model-first typed router for Unitflow.
|
|
4
|
+
|
|
5
|
+
Routes declare paths and codecs — never components, loaders, or data.
|
|
6
|
+
`Router.make` births two models the application only names: the engine
|
|
7
|
+
(navigation, current location) and a keyed per-route model (occupancy and
|
|
8
|
+
decoded params/search). Page data lives in ordinary Unitflow models gated on
|
|
9
|
+
route ports; React meets the router in exactly one place.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add @unitflow/router @unitflow/react @unitflow/core effect@4.0.0-beta.88
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Routes and models
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import * as Schema from "effect/Schema";
|
|
21
|
+
import { Router } from "@unitflow/router";
|
|
22
|
+
|
|
23
|
+
const userParams = Schema.Struct({ id: Schema.NumberFromString });
|
|
24
|
+
const userSearch = Schema.Struct({ page: Schema.NumberFromString });
|
|
25
|
+
|
|
26
|
+
export const HomeRoute = Router.route("home", { path: "/" });
|
|
27
|
+
export const UserRoute = Router.route("user", {
|
|
28
|
+
path: "/users/:id",
|
|
29
|
+
params: userParams,
|
|
30
|
+
search: userSearch,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const { NavigationModel, RouteModel } = Router.make(
|
|
34
|
+
"app/router",
|
|
35
|
+
Router.group(HomeRoute, UserRoute),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Registering the router types Link/redirect targets everywhere.
|
|
39
|
+
declare module "@unitflow/router" {
|
|
40
|
+
interface Register {
|
|
41
|
+
readonly router: typeof NavigationModel;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- `NavigationModel` — the engine: `inputs.navigate` (an event, like any
|
|
47
|
+
model input), `outputs.state`/`location`, `buildHref`/`buildLocation`.
|
|
48
|
+
- `RouteModel` — keyed by route id: `Model.get(RouteModel, "user")` returns
|
|
49
|
+
that route's unit with `outputs.opened`/`params`/`search`/`provided` as
|
|
50
|
+
`Option` ports, narrowed to THAT route's schemas.
|
|
51
|
+
|
|
52
|
+
## Page data: a model gated on route ports
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
class UserPageModel extends Model.Service<UserPageModel>()("app/UserPage")({
|
|
56
|
+
make: () =>
|
|
57
|
+
Effect.gen(function* () {
|
|
58
|
+
const unit = yield* Model.get(RouteModel, "user");
|
|
59
|
+
const user = yield* Query.make({
|
|
60
|
+
stores: { params: unit.outputs.params },
|
|
61
|
+
handler: ({ params }) =>
|
|
62
|
+
Option.isNone(params)
|
|
63
|
+
? Effect.fail("closed" as const)
|
|
64
|
+
: fetchUser(params.value.id), // id: number — decoded by the schema
|
|
65
|
+
});
|
|
66
|
+
return { inputs: {}, outputs: {}, ui: { user: user.state } };
|
|
67
|
+
}),
|
|
68
|
+
}) {}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Entering `/users/1` loads; changing the id reloads; leaving fails the query
|
|
72
|
+
into `"closed"`. No loader, no cache options — the model owns its data.
|
|
73
|
+
|
|
74
|
+
## React: one meeting point
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { Link, RouterView } from "@unitflow/router/react";
|
|
78
|
+
|
|
79
|
+
const UserPage = View.make(UserPageModel, ({ user }) => /* AsyncResult → JSX */);
|
|
80
|
+
|
|
81
|
+
export const AppView = RouterView.make(NavigationModel, {
|
|
82
|
+
routes: {
|
|
83
|
+
home: ({ children }) => (
|
|
84
|
+
<main>
|
|
85
|
+
<nav>
|
|
86
|
+
{/* to/params/search typed against the registered router */}
|
|
87
|
+
<Link to="/users/:id" params={{ id: 1 }} search={{ page: 1 }}>Ada</Link>
|
|
88
|
+
</nav>
|
|
89
|
+
{children}
|
|
90
|
+
</main>
|
|
91
|
+
),
|
|
92
|
+
user: UserPage, // a View.make component IS its own entry
|
|
93
|
+
},
|
|
94
|
+
notFound: () => <div>404</div>,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// main.tsx — the view carries its root model
|
|
98
|
+
const layer = AppView.model.layer.pipe(
|
|
99
|
+
Layer.provideMerge(UserPageModel.layer),
|
|
100
|
+
Layer.provideMerge(RouteModel.layer),
|
|
101
|
+
Layer.provideMerge(NavigationModel.layer),
|
|
102
|
+
Layer.provideMerge(Router.browserHistoryLayer), // or memoryHistoryLayer in tests
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
<Unitflow runtime={UnitflowRuntime.make(layer)} rootModel={AppView.model}>
|
|
106
|
+
{(pages) => <AppView unit={pages} />}
|
|
107
|
+
</Unitflow>;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Middleware: guards as services
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
class AuthGuard extends Router.Middleware<AuthGuard>()("app/AuthGuard")<{
|
|
114
|
+
readonly user: User;
|
|
115
|
+
}>() {}
|
|
116
|
+
|
|
117
|
+
const AuthGuardLive = AuthGuard.make((ctx) =>
|
|
118
|
+
Effect.gen(function* () {
|
|
119
|
+
const session = yield* SessionService; // the GUARD's dependency, not the router's
|
|
120
|
+
if (Option.isNone(session.user)) {
|
|
121
|
+
return yield* Effect.fail(new Router.RedirectError({ options: { to: "/login" } }));
|
|
122
|
+
}
|
|
123
|
+
return { user: session.user.value }; // Provides
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const adminRoutes = Router.group(Dashboard, Users).middleware(AuthGuard);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Guards run BEFORE a navigation commits: a blocked URL never flashes. The
|
|
131
|
+
returned value lands typed in the route unit's `provided` port —
|
|
132
|
+
`Option.some` whenever the route is open, because the guard passing is what
|
|
133
|
+
let it open.
|
|
134
|
+
|
|
135
|
+
## Complex search params
|
|
136
|
+
|
|
137
|
+
Schemas own the URL: literal unions, optional keys, and whole objects
|
|
138
|
+
(JSON-encoded into one param) decode into typed ports and encode back
|
|
139
|
+
through `Link`/`navigate`/`buildHref`.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
const search = Schema.Struct({
|
|
143
|
+
sort: Schema.Literals(["asc", "desc"]),
|
|
144
|
+
filter: Schema.fromJsonString(Schema.Struct({ role: Schema.String })),
|
|
145
|
+
q: Schema.optionalKey(Schema.String),
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## History is a capability
|
|
150
|
+
|
|
151
|
+
`Router.make` declares routes only; the environment decides how locations
|
|
152
|
+
are read and written: `Router.browserHistoryLayer`,
|
|
153
|
+
`Router.hashHistoryLayer`, or `Router.memoryHistoryLayer({ initialEntries })`
|
|
154
|
+
in tests. Forgetting one is a compile error, not a silent default.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * as Router from "./public.js";
|
|
2
|
+
export * as RouterGroup from "./router-group.js";
|
|
3
|
+
/**
|
|
4
|
+
* Registration point for the app's router. Declared HERE — in the package
|
|
5
|
+
* entry — because module augmentation only merges with an interface declared
|
|
6
|
+
* in the augmented module itself; a re-export would silently not merge.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* declare module "@unitflow/router" {
|
|
10
|
+
* interface Register {
|
|
11
|
+
* readonly router: typeof AppRouter;
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export interface Register {
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;CAAG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC"}
|
package/dist/public.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The curated public surface re-exported as the `Router` namespace.
|
|
3
|
+
* Everything from `router.ts` EXCEPT the controller plumbing
|
|
4
|
+
* (`RouterController`/`AnyRouterController`/`RouterControllerOf`): that is
|
|
5
|
+
* the synchronous read surface behind `outputs.api` — `react.tsx` and the
|
|
6
|
+
* `buildLocation`/`buildHref`/`matchRoute` helpers use it internally, but
|
|
7
|
+
* application code should never need to name it.
|
|
8
|
+
*/
|
|
9
|
+
export { search, schemaSearch, isRoute, route, group, makeGroup, add, merge, prefix, routes, RedirectError, NotFoundError, isRedirectError, isNotFoundError, Middleware, make, History, browserHistoryLayer, hashHistoryLayer, memoryHistoryLayer, createMemoryHistory, createBrowserHistory, createHashHistory, defaultParseSearch, defaultStringifySearch, } from "./router.js";
|
|
10
|
+
export type { SearchPrimitive, SearchValue, RawSearch, SearchRecord, PathParams, JoinPath, SearchCodec, AnySearchCodec, AnySchemaCodec, RouteContext, RouteOptions, Route, MiddlewareContext, MiddlewareHandler, MiddlewareClass, AnyMiddleware, ProvidesOf, RouteGroup, AnyRouteGroup, RoutesOf, ParsedLocation, RouterHistory, HistoryFactory, RouteMatch, RouterState, RouterOptions, ActiveOptions, Blocker, NavigatePayload, RouterShape, RouterModel, RouterTargets, RouteModel, PagesModel, AnyPagesModel, PagesShape, PageMap, RouteUnitShape, RouteShapes, RouteIds, AnyRouter, RegisteredRouter, RouterGroupOf, RouterIdOf, RouterRoutes, RoutePath, RouteByPath, MatchByPath, MatchUnion, ToOptions, NavigateOptions, } from "./router.js";
|
|
11
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../src/public.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAEL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,KAAK,EACL,KAAK,EACL,SAAS,EACT,GAAG,EACH,KAAK,EACL,MAAM,EACN,MAAM,EAEN,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EAEf,UAAU,EAEV,IAAI,EAGJ,OAAO,EACP,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,eAAe,EACf,WAAW,EACX,SAAS,EACT,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,WAAW,EACX,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,aAAa,EACb,aAAa,EACb,OAAO,EACP,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,OAAO,EACP,cAAc,EACd,WAAW,EACX,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,EACT,eAAe,GAChB,MAAM,aAAa,CAAC"}
|
package/dist/public.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The curated public surface re-exported as the `Router` namespace.
|
|
3
|
+
* Everything from `router.ts` EXCEPT the controller plumbing
|
|
4
|
+
* (`RouterController`/`AnyRouterController`/`RouterControllerOf`): that is
|
|
5
|
+
* the synchronous read surface behind `outputs.api` — `react.tsx` and the
|
|
6
|
+
* `buildLocation`/`buildHref`/`matchRoute` helpers use it internally, but
|
|
7
|
+
* application code should never need to name it.
|
|
8
|
+
*/
|
|
9
|
+
export {
|
|
10
|
+
// route + group construction
|
|
11
|
+
search, schemaSearch, isRoute, route, group, makeGroup, add, merge, prefix, routes,
|
|
12
|
+
// redirect / not-found
|
|
13
|
+
RedirectError, NotFoundError, isRedirectError, isNotFoundError,
|
|
14
|
+
// middleware
|
|
15
|
+
Middleware,
|
|
16
|
+
// router model
|
|
17
|
+
make,
|
|
18
|
+
// histories — provided as layers; the create* factories stay exported for
|
|
19
|
+
// custom History implementations
|
|
20
|
+
History, browserHistoryLayer, hashHistoryLayer, memoryHistoryLayer, createMemoryHistory, createBrowserHistory, createHashHistory, defaultParseSearch, defaultStringifySearch, } from "./router.js";
|
|
21
|
+
//# sourceMappingURL=public.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.js","sourceRoot":"","sources":["../src/public.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO;AACL,6BAA6B;AAC7B,MAAM,EACN,YAAY,EACZ,OAAO,EACP,KAAK,EACL,KAAK,EACL,SAAS,EACT,GAAG,EACH,KAAK,EACL,MAAM,EACN,MAAM;AACN,uBAAuB;AACvB,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe;AACf,aAAa;AACb,UAAU;AACV,eAAe;AACf,IAAI;AACJ,0EAA0E;AAC1E,iCAAiC;AACjC,OAAO,EACP,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type Model } from "@unitflow/react";
|
|
3
|
+
import * as Router from "./router.js";
|
|
4
|
+
type Controller<M extends Router.AnyRouter> = Router.RouterControllerOf<M>;
|
|
5
|
+
export interface BoundRouter<M extends Router.AnyRouter = Router.RegisteredRouter> {
|
|
6
|
+
/** Phantom inference anchor: every other occurrence of `M` here sits
|
|
7
|
+
* behind a conditional type (`RouterRoutes<M>` etc.) TypeScript cannot
|
|
8
|
+
* invert, so without this marker `M` silently falls back to its default
|
|
9
|
+
* and `Link`/`MatchRoute` props stop being route-typed. Never set at
|
|
10
|
+
* runtime. */
|
|
11
|
+
readonly "~model"?: M;
|
|
12
|
+
readonly state: Router.RouterState<Router.RouterRoutes<M>>;
|
|
13
|
+
readonly location: Router.ParsedLocation;
|
|
14
|
+
readonly matches: ReadonlyArray<Router.MatchUnion<M>>;
|
|
15
|
+
readonly api: Controller<M>;
|
|
16
|
+
readonly navigate: (options: Router.NavigateOptions<Controller<M>, Router.RoutePath<Controller<M>>>) => void;
|
|
17
|
+
}
|
|
18
|
+
export type RouteComponent<M extends Router.AnyRouter = Router.RegisteredRouter, Match extends Router.RouteMatch = Router.MatchUnion<M>, Units = void> = (props: {
|
|
19
|
+
readonly router: BoundRouter<M>;
|
|
20
|
+
readonly match: Match;
|
|
21
|
+
/** Extra units the OWNING view passed through `RouterView`'s `units`
|
|
22
|
+
* prop — for anything that is not a route's page model. */
|
|
23
|
+
readonly units: Units;
|
|
24
|
+
readonly children: React.ReactNode;
|
|
25
|
+
}) => React.ReactNode;
|
|
26
|
+
/** A model-bound view (what `View.make` returns): dropping it straight
|
|
27
|
+
* into the routes map makes the router lease its model and hand the unit
|
|
28
|
+
* back in — `user: UserPage` is the whole stitching. Deliberately typed
|
|
29
|
+
* WITHOUT a call signature: a second callable union member would destroy
|
|
30
|
+
* contextual typing of plain function entries. */
|
|
31
|
+
export interface ModelViewEntry {
|
|
32
|
+
readonly model: Model.AnyService;
|
|
33
|
+
}
|
|
34
|
+
type BoundaryComponent<M extends Router.AnyRouter = Router.RegisteredRouter> = (props: {
|
|
35
|
+
readonly router: BoundRouter<M>;
|
|
36
|
+
readonly match?: Router.RouteMatch;
|
|
37
|
+
readonly error?: unknown;
|
|
38
|
+
}) => React.ReactNode;
|
|
39
|
+
type RouteById<M extends Router.AnyRouter, Id> = Extract<Router.RouterRoutes<M>, {
|
|
40
|
+
readonly id: Id;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* The one place a router meets rendering: a route only declares `model` (or
|
|
44
|
+
* nothing) — never a component. This map supplies the actual view for each
|
|
45
|
+
* route id, plus the pending/error/not-found boundaries, entirely outside
|
|
46
|
+
* `@unitflow/router` itself. Keys are constrained to the router's actual
|
|
47
|
+
* route ids (a typo will not compile), and each view's `match` is narrowed
|
|
48
|
+
* to ITS route's params/search types.
|
|
49
|
+
*/
|
|
50
|
+
export interface RouterViews<M extends Router.AnyRouter = Router.RegisteredRouter, Units = void> {
|
|
51
|
+
readonly routes: {
|
|
52
|
+
readonly [Id in Router.RouteIds<Router.RouterGroupOf<M>>]?: RouteComponent<M, Router.RouteMatch<RouteById<M, Id>>, Units> | ModelViewEntry;
|
|
53
|
+
};
|
|
54
|
+
readonly pending?: BoundaryComponent<M>;
|
|
55
|
+
readonly error?: BoundaryComponent<M>;
|
|
56
|
+
readonly notFound?: BoundaryComponent<M>;
|
|
57
|
+
}
|
|
58
|
+
export interface MatchesProps<M extends Router.AnyRouter = Router.RegisteredRouter, Units = void> {
|
|
59
|
+
readonly router: BoundRouter<M>;
|
|
60
|
+
readonly views: RouterViews<M, Units>;
|
|
61
|
+
readonly units: Units;
|
|
62
|
+
readonly pages: Readonly<Record<string, unknown>>;
|
|
63
|
+
}
|
|
64
|
+
export declare function Matches<M extends Router.AnyRouter = Router.RegisteredRouter, Units = void>({ router, views, units, pages, }: MatchesProps<M, Units>): React.ReactNode;
|
|
65
|
+
/** The extra prop the router view takes when its views need child units:
|
|
66
|
+
* absent for `Units = void`, required otherwise. */
|
|
67
|
+
type UnitsProp<Units> = [Units] extends [void] ? {
|
|
68
|
+
readonly units?: undefined;
|
|
69
|
+
} : {
|
|
70
|
+
readonly units: Units;
|
|
71
|
+
};
|
|
72
|
+
/** What `RouterView.make` returns: the outlet component, carrying the
|
|
73
|
+
* pages model it should be rooted with (`rootModel={AppView.model}`). */
|
|
74
|
+
export type RouterViewComponent<M extends Router.AnyRouter, Units> = React.FC<{
|
|
75
|
+
readonly unit: Model.UnitPorts;
|
|
76
|
+
} & UnitsProp<Units>> & {
|
|
77
|
+
/** The root model for this view tree: owns the router and every page
|
|
78
|
+
* model stitched into the views map. */
|
|
79
|
+
readonly model: Router.PagesModel<Router.RouterIdOf<M>, Router.RouterGroupOf<M>, Router.PageMap<Router.RouterGroupOf<M>>>;
|
|
80
|
+
};
|
|
81
|
+
export declare const RouterView: {
|
|
82
|
+
make: <M extends Router.AnyRouter, Units = void>(router: M, views: RouterViews<M, Units>) => RouterViewComponent<M, Units>;
|
|
83
|
+
};
|
|
84
|
+
export declare const View: {
|
|
85
|
+
make: <M extends Router.AnyRouter, Units = void>(router: M, views: RouterViews<M, Units>) => RouterViewComponent<M, Units>;
|
|
86
|
+
};
|
|
87
|
+
type AnchorProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "children" | "href">;
|
|
88
|
+
type LinkState = {
|
|
89
|
+
readonly isActive: boolean;
|
|
90
|
+
readonly isTransitioning: boolean;
|
|
91
|
+
};
|
|
92
|
+
type StateProps = AnchorProps & {
|
|
93
|
+
readonly [key: `data-${string}`]: unknown;
|
|
94
|
+
};
|
|
95
|
+
export type LinkProps<M extends Router.AnyRouter = Router.RegisteredRouter, To extends Router.RoutePath<M> = Router.RoutePath<M>> = AnchorProps & Router.NavigateOptions<M, To> & {
|
|
96
|
+
/** Only needed OUTSIDE a RouterView (or with several routers): under
|
|
97
|
+
* one, the bound router arrives via context and types come from the
|
|
98
|
+
* registered router. */
|
|
99
|
+
readonly router?: BoundRouter<M>;
|
|
100
|
+
readonly children?: React.ReactNode | ((state: LinkState) => React.ReactNode);
|
|
101
|
+
readonly activeProps?: StateProps | (() => StateProps);
|
|
102
|
+
readonly inactiveProps?: StateProps | (() => StateProps);
|
|
103
|
+
};
|
|
104
|
+
export type LinkComponent = <M extends Router.AnyRouter = Router.RegisteredRouter, const To extends Router.RoutePath<M> = Router.RoutePath<M>>(props: LinkProps<M, To> & {
|
|
105
|
+
readonly ref?: React.Ref<HTMLAnchorElement>;
|
|
106
|
+
}) => React.ReactElement;
|
|
107
|
+
export declare const Link: LinkComponent;
|
|
108
|
+
export type NavigateProps<M extends Router.AnyRouter = Router.RegisteredRouter, To extends Router.RoutePath<M> = Router.RoutePath<M>> = Router.NavigateOptions<M, To> & {
|
|
109
|
+
readonly router?: BoundRouter<M>;
|
|
110
|
+
};
|
|
111
|
+
export declare function Navigate<M extends Router.AnyRouter = Router.RegisteredRouter, To extends Router.RoutePath<M> = Router.RoutePath<M>>(props: NavigateProps<M, To>): null;
|
|
112
|
+
export type MatchRouteProps<M extends Router.AnyRouter = Router.RegisteredRouter, To extends Router.RoutePath<M> = Router.RoutePath<M>> = Router.ToOptions<M, To> & Router.ActiveOptions & {
|
|
113
|
+
readonly router?: BoundRouter<M>;
|
|
114
|
+
readonly children?: React.ReactNode | ((state: {
|
|
115
|
+
readonly isActive: boolean;
|
|
116
|
+
}) => React.ReactNode);
|
|
117
|
+
};
|
|
118
|
+
export declare function MatchRoute<M extends Router.AnyRouter = Router.RegisteredRouter, const To extends Router.RoutePath<M> = Router.RoutePath<M>>(props: MatchRouteProps<M, To>): React.ReactNode;
|
|
119
|
+
export type CreatedLinkComponent = <M extends Router.AnyRouter = Router.RegisteredRouter, const To extends Router.RoutePath<M> = Router.RoutePath<M>>(props: LinkProps<M, To> & {
|
|
120
|
+
readonly ref?: React.Ref<HTMLAnchorElement>;
|
|
121
|
+
}) => React.ReactElement;
|
|
122
|
+
export declare const createLink: <Props extends AnchorProps>(Component: React.ComponentType<Props & React.RefAttributes<HTMLAnchorElement>>) => CreatedLinkComponent;
|
|
123
|
+
export declare const linkOptions: <const Options>(options: Options) => Options;
|
|
124
|
+
export {};
|
|
125
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { View as UnitView } from "@unitflow/react";
|
|
4
|
+
import * as Router from "./router.js";
|
|
5
|
+
const renderBoundary = (Component, router, state) => {
|
|
6
|
+
if (Component === undefined)
|
|
7
|
+
return null;
|
|
8
|
+
const match = state.matches.at(-1);
|
|
9
|
+
return match === undefined
|
|
10
|
+
? _jsx(Component, { router: router, error: state.error })
|
|
11
|
+
: _jsx(Component, { router: router, match: match, error: state.error });
|
|
12
|
+
};
|
|
13
|
+
export function Matches({ router, views, units, pages, }) {
|
|
14
|
+
const state = router.state;
|
|
15
|
+
if (state.status === "error")
|
|
16
|
+
return renderBoundary(views.error, router, state);
|
|
17
|
+
if (state.status === "not-found")
|
|
18
|
+
return renderBoundary(views.notFound, router, state);
|
|
19
|
+
if (state.status === "pending" && state.matches.length === 0) {
|
|
20
|
+
return views.pending === undefined ? null : _jsx(_Fragment, { children: views.pending({ router }) });
|
|
21
|
+
}
|
|
22
|
+
return (_jsx(MatchRenderer, { router: router, views: views, units: units, pages: pages, state: state, index: 0 }));
|
|
23
|
+
}
|
|
24
|
+
const makeRouterView = (router, views) => {
|
|
25
|
+
// Stitch: pull the models out of the views map and let the router build
|
|
26
|
+
// its pages model around them.
|
|
27
|
+
const pageModels = {};
|
|
28
|
+
for (const [routeId, entry] of Object.entries(views.routes)) {
|
|
29
|
+
if (typeof entry === "function" && "model" in entry) {
|
|
30
|
+
pageModels[routeId] = entry.model;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const pagesModel = Router.makePages(router, pageModels);
|
|
34
|
+
const Bound = UnitView.make(
|
|
35
|
+
// The pages model carries its router value (typed opaquely — cycle
|
|
36
|
+
// breaker); the inner view binds the ROUTER unit for state/navigation.
|
|
37
|
+
pagesModel.router, (bound, extra) => (_jsx(BoundRouterContext.Provider, { value: bound, children: _jsx(Matches, { router: bound, views: views, units: extra.forwardedUnits, pages: extra.pages }) })));
|
|
38
|
+
const Component = (props) => {
|
|
39
|
+
// pages.ui = { router: <router unit>, ...page units by route id }.
|
|
40
|
+
const pagesUi = props.unit.ui;
|
|
41
|
+
return (_jsx(Bound, { unit: pagesUi["router"], forwardedUnits: props.units, pages: pagesUi }));
|
|
42
|
+
};
|
|
43
|
+
Component.displayName = "RouterView";
|
|
44
|
+
return Object.assign(Component, { model: pagesModel });
|
|
45
|
+
};
|
|
46
|
+
export const RouterView = { make: makeRouterView };
|
|
47
|
+
export const View = RouterView;
|
|
48
|
+
const MatchRenderer = ({ router, views, units, pages, state, index, }) => {
|
|
49
|
+
const match = state.matches[index];
|
|
50
|
+
if (match === undefined)
|
|
51
|
+
return null;
|
|
52
|
+
// The runtime id is erased to `string`; the map itself is keyed strictly.
|
|
53
|
+
// eslint-disable-next-line revizo/no-type-assertion
|
|
54
|
+
const entry = views.routes[match.route.id];
|
|
55
|
+
// `null` (not an empty renderer element) when no deeper match exists, so
|
|
56
|
+
// a layout's `children ?? fallback` — and a parent page deciding between
|
|
57
|
+
// its own content and a child's — actually work.
|
|
58
|
+
const child = index + 1 < state.matches.length ? (_jsx(MatchRenderer, { router: router, views: views, units: units, pages: pages, state: state, index: index + 1 })) : null;
|
|
59
|
+
if (entry === undefined)
|
|
60
|
+
return child;
|
|
61
|
+
if ("model" in entry) {
|
|
62
|
+
// A model-bound view: its unit was leased by the pages model.
|
|
63
|
+
const PageView = entry;
|
|
64
|
+
return (_jsx(PageView, { unit: pages[match.route.id], children: child }));
|
|
65
|
+
}
|
|
66
|
+
const RouteView = entry;
|
|
67
|
+
return (_jsx(RouteView, { router: router, match: match, units: units, children: child }));
|
|
68
|
+
};
|
|
69
|
+
/** The bound router `RouterView` provides to everything it renders, so
|
|
70
|
+
* `Link`/`Navigate`/`MatchRoute` need no `router` prop under it. NOT a way
|
|
71
|
+
* for views to summon models — the value is the already-bound unit the
|
|
72
|
+
* RouterView owns; this only spares threading it through every level. */
|
|
73
|
+
const BoundRouterContext = React.createContext(null);
|
|
74
|
+
const useBoundRouter = (explicit, who) => {
|
|
75
|
+
const fromContext = React.useContext(BoundRouterContext);
|
|
76
|
+
const router = explicit ?? fromContext;
|
|
77
|
+
if (router === null || router === undefined) {
|
|
78
|
+
throw new Error(`Unitflow ${who} needs a RouterView above it (or an explicit router prop).`);
|
|
79
|
+
}
|
|
80
|
+
return router;
|
|
81
|
+
};
|
|
82
|
+
export const Link = React.forwardRef(function Link(props, ref) {
|
|
83
|
+
const { router: routerProp, activeProps, inactiveProps, children, onClick, ...rest } = props;
|
|
84
|
+
const router = useBoundRouter(routerProp, "Link");
|
|
85
|
+
const href = router.api.buildHref(rest);
|
|
86
|
+
const isActive = router.api.matchRoute(rest);
|
|
87
|
+
const stateProps = resolveStateProps(isActive ? activeProps : inactiveProps);
|
|
88
|
+
const handleClick = (event) => {
|
|
89
|
+
onClick?.(event);
|
|
90
|
+
if (shouldHandleClick(event, props)) {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
router.navigate(rest);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const renderedChildren = typeof children === "function" ? children({ isActive, isTransitioning: false }) : children;
|
|
96
|
+
return (_jsx("a", { ...mergeProps(rest, stateProps), href: href, ref: ref, "data-status": isActive ? "active" : undefined, onClick: handleClick, children: renderedChildren }));
|
|
97
|
+
});
|
|
98
|
+
export function Navigate(props) {
|
|
99
|
+
const { router: routerProp, ...options } = props;
|
|
100
|
+
const router = useBoundRouter(routerProp, "Navigate");
|
|
101
|
+
const navigate = router.navigate;
|
|
102
|
+
React.useEffect(() => {
|
|
103
|
+
navigate(options);
|
|
104
|
+
// Re-fires only on a new target, not on unrelated renders.
|
|
105
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
106
|
+
}, [navigate, JSON.stringify(options)]);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
export function MatchRoute(props) {
|
|
110
|
+
const { router: routerProp, children, ...rest } = props;
|
|
111
|
+
const router = useBoundRouter(routerProp, "MatchRoute");
|
|
112
|
+
const isActive = router.api.matchRoute(rest);
|
|
113
|
+
if (typeof children === "function")
|
|
114
|
+
return children({ isActive });
|
|
115
|
+
return isActive ? children : null;
|
|
116
|
+
}
|
|
117
|
+
export const createLink = (Component) => React.forwardRef(function CreatedLink(props, ref) {
|
|
118
|
+
const { router: routerProp, ...rest } = props;
|
|
119
|
+
const router = useBoundRouter(routerProp, "createLink");
|
|
120
|
+
const href = router.api.buildHref(rest);
|
|
121
|
+
return _jsx(Component, { ...rest, href: href, ref: ref });
|
|
122
|
+
});
|
|
123
|
+
export const linkOptions = (options) => options;
|
|
124
|
+
const resolveStateProps = (props) => (typeof props === "function" ? props() : props);
|
|
125
|
+
const mergeProps = (base, state) => {
|
|
126
|
+
if (state === undefined)
|
|
127
|
+
return base;
|
|
128
|
+
return {
|
|
129
|
+
...base,
|
|
130
|
+
...state,
|
|
131
|
+
className: [base.className, state.className].filter(Boolean).join(" ") || undefined,
|
|
132
|
+
style: { ...base.style, ...state.style },
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
const shouldHandleClick = (event, props) => {
|
|
136
|
+
if (event.defaultPrevented)
|
|
137
|
+
return false;
|
|
138
|
+
if (props.reloadDocument === true)
|
|
139
|
+
return false;
|
|
140
|
+
if (event.button !== 0)
|
|
141
|
+
return false;
|
|
142
|
+
if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey)
|
|
143
|
+
return false;
|
|
144
|
+
if (props.target !== undefined && props.target !== "_self")
|
|
145
|
+
return false;
|
|
146
|
+
if (props.download !== undefined)
|
|
147
|
+
return false;
|
|
148
|
+
return true;
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-group.d.ts","sourceRoot":"","sources":["../src/router-group.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,GAAG,EACH,KAAK,EACL,SAAS,IAAI,IAAI,EACjB,KAAK,EACL,MAAM,EACN,MAAM,GACP,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-group.js","sourceRoot":"","sources":["../src/router-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,GAAG,EACH,KAAK,EACL,SAAS,IAAI,IAAI,EACjB,KAAK,EACL,MAAM,EACN,MAAM,GACP,MAAM,aAAa,CAAC"}
|