@xmachines/play-xstate 2.2.0 → 4.0.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 +158 -54
- package/dist/capabilities.d.ts +92 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +4 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/define-player.d.ts +7 -1
- package/dist/define-player.d.ts.map +1 -1
- package/dist/define-player.js +9 -60
- package/dist/define-player.js.map +1 -1
- package/dist/errors.d.ts +29 -26
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +53 -35
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +74 -114
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +94 -223
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +1 -36
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +2 -76
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +11 -0
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/derive-route.d.ts +81 -2
- package/dist/routing/derive-route.d.ts.map +1 -1
- package/dist/routing/derive-route.js +97 -3
- package/dist/routing/derive-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +8 -2
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +170 -43
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +1 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/types.d.ts +9 -5
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/state-meta.d.ts +52 -0
- package/dist/state-meta.d.ts.map +1 -0
- package/dist/state-meta.js +77 -0
- package/dist/state-meta.js.map +1 -0
- package/dist/types.d.ts +18 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +1 -1
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +35 -17
- package/dist/view/derive-current-view.js.map +1 -1
- package/dist/with-routing.d.ts +45 -0
- package/dist/with-routing.d.ts.map +1 -0
- package/dist/with-routing.js +78 -0
- package/dist/with-routing.js.map +1 -0
- package/dist/with-view.d.ts +42 -0
- package/dist/with-view.d.ts.map +1 -0
- package/dist/with-view.js +150 -0
- package/dist/with-view.js.map +1 -0
- package/package.json +39 -18
- package/dist/guards/compose.d.ts +0 -158
- package/dist/guards/compose.d.ts.map +0 -1
- package/dist/guards/compose.js +0 -188
- package/dist/guards/compose.js.map +0 -1
- package/dist/guards/helpers.d.ts +0 -62
- package/dist/guards/helpers.d.ts.map +0 -1
- package/dist/guards/helpers.js +0 -85
- package/dist/guards/helpers.js.map +0 -1
- package/dist/guards/index.d.ts +0 -20
- package/dist/guards/index.d.ts.map +0 -1
- package/dist/guards/index.js +0 -18
- package/dist/guards/index.js.map +0 -1
- package/dist/guards/types.d.ts +0 -22
- package/dist/guards/types.d.ts.map +0 -1
- package/dist/guards/types.js +0 -2
- package/dist/guards/types.js.map +0 -1
|
@@ -52,6 +52,17 @@ export const deriveInitialRoute = (machine, input) => {
|
|
|
52
52
|
// that snapshot also has no route metadata. Report "no initial route to derive".
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
+
// The SAME failure, reported the other way. XState 5.32 threw out of
|
|
56
|
+
// `initialTransition` for a context factory that throws, and 5.33 returns an
|
|
57
|
+
// error-status snapshot instead, with the reason on `snapshot.error`. The catch above
|
|
58
|
+
// therefore stopped firing, and a machine whose context never built derived the route
|
|
59
|
+
// of its initial state — `/login` for a factory that threw — which a bridge then took
|
|
60
|
+
// as the place of the actor.
|
|
61
|
+
//
|
|
62
|
+
// Both shapes mean the same thing, so both answer the same way. The status is the
|
|
63
|
+
// question, and it holds whichever way a later release reports the failure.
|
|
64
|
+
if (initialSnapshot.status === "error")
|
|
65
|
+
return null;
|
|
55
66
|
return deriveCurrentRoute(initialSnapshot);
|
|
56
67
|
};
|
|
57
68
|
//# sourceMappingURL=derive-initial-route.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-initial-route.js","sourceRoot":"","sources":["../../src/routing/derive-initial-route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiD,MAAM,QAAQ,CAAC;AAE1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAwB,EAAE,KAAe,EAAiB,EAAE;IAC9F,IAAI,eAAmC,CAAC;IACxC,IAAI,CAAC;QACJ,CAAC,eAAe,CAAC,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACR,gFAAgF;QAChF,oFAAoF;QACpF,qFAAqF;QACrF,iFAAiF;QACjF,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,kBAAkB,CAAC,eAAe,CAAC,CAAC;AAC5C,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"derive-initial-route.js","sourceRoot":"","sources":["../../src/routing/derive-initial-route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiD,MAAM,QAAQ,CAAC;AAE1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAwB,EAAE,KAAe,EAAiB,EAAE;IAC9F,IAAI,eAAmC,CAAC;IACxC,IAAI,CAAC;QACJ,CAAC,eAAe,CAAC,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACR,gFAAgF;QAChF,oFAAoF;QACpF,qFAAqF;QACrF,iFAAiF;QACjF,OAAO,IAAI,CAAC;IACb,CAAC;IAED,qEAAqE;IACrE,6EAA6E;IAC7E,sFAAsF;IACtF,sFAAsF;IACtF,sFAAsF;IACtF,6BAA6B;IAC7B,EAAE;IACF,kFAAkF;IAClF,4EAA4E;IAC5E,IAAI,eAAe,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAEpD,OAAO,kBAAkB,CAAC,eAAe,CAAC,CAAC;AAC5C,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PlayRouteEvent, RouteData } from "@xmachines/play-router";
|
|
1
2
|
import type { RouteMetadata } from "./types.js";
|
|
2
3
|
/**
|
|
3
4
|
* Derives the route from the metadata of an XState state
|
|
@@ -18,7 +19,7 @@ import type { RouteMetadata } from "./types.js";
|
|
|
18
19
|
* @example
|
|
19
20
|
* The basic read of a route
|
|
20
21
|
* ```typescript
|
|
21
|
-
* import { deriveRoute } from "@xmachines/play-xstate";
|
|
22
|
+
* import { deriveRoute } from "@xmachines/play-xstate/routing";
|
|
22
23
|
* import { setup } from "xstate";
|
|
23
24
|
*
|
|
24
25
|
* const machine = setup({}).createMachine({
|
|
@@ -101,6 +102,84 @@ export declare const deriveRoute: (stateMeta: Record<string, unknown>) => string
|
|
|
101
102
|
* @throws {InvalidRouteMetadataError} When the form of the route is invalid
|
|
102
103
|
*/
|
|
103
104
|
export declare const normalizeRoute: (route: RouteMetadata, source?: string) => string;
|
|
105
|
+
/**
|
|
106
|
+
* Reads the `reenter` flag of the route metadata.
|
|
107
|
+
*
|
|
108
|
+
* The string form of the metadata declares no flag, and the object form declares the
|
|
109
|
+
* flag only when it wants one. Both therefore give `false`, which is the default of
|
|
110
|
+
* XState for a transition. A state without a route gives `false` too, so the caller
|
|
111
|
+
* needs no test of its own for that case.
|
|
112
|
+
*
|
|
113
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
114
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
115
|
+
*
|
|
116
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
117
|
+
* `undefined` for a state that declares no route
|
|
118
|
+
* @returns The declared flag, or `false` where the metadata declares none
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* routeReenter("/dashboard"); // false
|
|
123
|
+
* routeReenter({ path: "/dashboard" }); // false
|
|
124
|
+
* routeReenter({ path: "/dashboard", reenter: true }); // true
|
|
125
|
+
* routeReenter(undefined); // false
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare const routeReenter: (route: RouteMetadata | undefined) => boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Reads the extra data that a route declares, resolved for one event.
|
|
131
|
+
*
|
|
132
|
+
* The field holds a literal value or a function of `{ context, event }`, which is the
|
|
133
|
+
* `WithDynamicParams` shape of XState. This function collapses the two into the value.
|
|
134
|
+
*
|
|
135
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
136
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
137
|
+
*
|
|
138
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
139
|
+
* `undefined` for a state that declares no route
|
|
140
|
+
* @param args - The context of the machine and the `play.route` event that asks for the
|
|
141
|
+
* route. The resolver reads them.
|
|
142
|
+
* @returns The data, or `undefined` where the route declares none
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* routeData({ path: "/a", data: { titleKey: "a" } }, args); // { titleKey: "a" }
|
|
147
|
+
* routeData({ path: "/a", data: ({ event }) => ({ to: event.to }) }, args);
|
|
148
|
+
* routeData("/a", args); // undefined
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export declare const routeData: (route: RouteMetadata | undefined, args: {
|
|
152
|
+
context: unknown;
|
|
153
|
+
event: PlayRouteEvent;
|
|
154
|
+
}) => RouteData | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Reads the placement of the generated `play.route` transition.
|
|
157
|
+
*
|
|
158
|
+
* `"root"` is the default, and it is the placement of XState: every route transition
|
|
159
|
+
* sits on the root of the machine. `"local"` moves the transition to the parent of the
|
|
160
|
+
* state, and `"both"` puts one transition in each place.
|
|
161
|
+
*
|
|
162
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
163
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
164
|
+
*
|
|
165
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
166
|
+
* `undefined` for a state that declares no route
|
|
167
|
+
* @param source - The `PlayError.scope` value to report for an unknown placement
|
|
168
|
+
* @returns The declared placement, and `"root"` where the metadata declares none
|
|
169
|
+
* @throws {InvalidRouteHandlerError} When the object declares a `handler` that is not
|
|
170
|
+
* `"root"`, `"local"`, or `"both"`. A typo would otherwise fall back to a placement
|
|
171
|
+
* that the author did not ask for, and it would change which states a route reaches.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* routeHandler("/dashboard"); // "root"
|
|
176
|
+
* routeHandler({ path: "/dashboard" }); // "root"
|
|
177
|
+
* routeHandler({ path: "/dashboard", handler: "local" }); // "local"
|
|
178
|
+
* routeHandler({ path: "/dashboard", handler: "both" }); // "both"
|
|
179
|
+
* routeHandler({ path: "/dashboard", handler: "locale" }); // throws
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export declare const routeHandler: (route: RouteMetadata | undefined, source?: string) => "root" | "local" | "both";
|
|
104
183
|
/**
|
|
105
184
|
* Tells you if the route path is absolute
|
|
106
185
|
*
|
|
@@ -113,7 +192,7 @@ export declare const normalizeRoute: (route: RouteMetadata, source?: string) =>
|
|
|
113
192
|
*
|
|
114
193
|
* @example
|
|
115
194
|
* ```typescript
|
|
116
|
-
* import { isAbsoluteRoute } from "@xmachines/play-xstate";
|
|
195
|
+
* import { isAbsoluteRoute } from "@xmachines/play-xstate/routing";
|
|
117
196
|
*
|
|
118
197
|
* console.log(isAbsoluteRoute("/dashboard")); // true
|
|
119
198
|
* console.log(isAbsoluteRoute("settings")); // false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,GAAG,IAuBzE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,aAAa,EAAE,eAAsB,KAAG,MAW7E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,OAE9C,CAAC"}
|
|
1
|
+
{"version":3,"file":"derive-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,GAAG,IAuBzE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,aAAa,EAAE,eAAsB,KAAG,MAW7E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,aAAa,GAAG,SAAS,KAAG,OACuB,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,SAAS,GACrB,OAAO,aAAa,GAAG,SAAS,EAChC,MAAM;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,KAC/C,SAAS,GAAG,SAOd,CAAC;AAKF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,YAAY,GACxB,OAAO,aAAa,GAAG,SAAS,EAChC,eAAqC,KACnC,MAAM,GAAG,OAAO,GAAG,MAUrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,OAE9C,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InvalidRouteMetadataError } from "../errors.js";
|
|
1
|
+
import { InvalidRouteHandlerError, InvalidRouteMetadataError } from "../errors.js";
|
|
2
2
|
/**
|
|
3
3
|
* Derives the route from the metadata of an XState state
|
|
4
4
|
*
|
|
@@ -18,7 +18,7 @@ import { InvalidRouteMetadataError } from "../errors.js";
|
|
|
18
18
|
* @example
|
|
19
19
|
* The basic read of a route
|
|
20
20
|
* ```typescript
|
|
21
|
-
* import { deriveRoute } from "@xmachines/play-xstate";
|
|
21
|
+
* import { deriveRoute } from "@xmachines/play-xstate/routing";
|
|
22
22
|
* import { setup } from "xstate";
|
|
23
23
|
*
|
|
24
24
|
* const machine = setup({}).createMachine({
|
|
@@ -135,6 +135,100 @@ export const normalizeRoute = (route, source = "deriveRoute") => {
|
|
|
135
135
|
}
|
|
136
136
|
throw new InvalidRouteMetadataError(route, source);
|
|
137
137
|
};
|
|
138
|
+
/**
|
|
139
|
+
* Reads the `reenter` flag of the route metadata.
|
|
140
|
+
*
|
|
141
|
+
* The string form of the metadata declares no flag, and the object form declares the
|
|
142
|
+
* flag only when it wants one. Both therefore give `false`, which is the default of
|
|
143
|
+
* XState for a transition. A state without a route gives `false` too, so the caller
|
|
144
|
+
* needs no test of its own for that case.
|
|
145
|
+
*
|
|
146
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
147
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
148
|
+
*
|
|
149
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
150
|
+
* `undefined` for a state that declares no route
|
|
151
|
+
* @returns The declared flag, or `false` where the metadata declares none
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* routeReenter("/dashboard"); // false
|
|
156
|
+
* routeReenter({ path: "/dashboard" }); // false
|
|
157
|
+
* routeReenter({ path: "/dashboard", reenter: true }); // true
|
|
158
|
+
* routeReenter(undefined); // false
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export const routeReenter = (route) => typeof route === "object" && route !== null && route.reenter === true;
|
|
162
|
+
/**
|
|
163
|
+
* Reads the extra data that a route declares, resolved for one event.
|
|
164
|
+
*
|
|
165
|
+
* The field holds a literal value or a function of `{ context, event }`, which is the
|
|
166
|
+
* `WithDynamicParams` shape of XState. This function collapses the two into the value.
|
|
167
|
+
*
|
|
168
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
169
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
170
|
+
*
|
|
171
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
172
|
+
* `undefined` for a state that declares no route
|
|
173
|
+
* @param args - The context of the machine and the `play.route` event that asks for the
|
|
174
|
+
* route. The resolver reads them.
|
|
175
|
+
* @returns The data, or `undefined` where the route declares none
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* routeData({ path: "/a", data: { titleKey: "a" } }, args); // { titleKey: "a" }
|
|
180
|
+
* routeData({ path: "/a", data: ({ event }) => ({ to: event.to }) }, args);
|
|
181
|
+
* routeData("/a", args); // undefined
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export const routeData = (route, args) => {
|
|
185
|
+
if (typeof route !== "object" || route === null)
|
|
186
|
+
return undefined;
|
|
187
|
+
const data = route.data;
|
|
188
|
+
if (data === undefined)
|
|
189
|
+
return undefined;
|
|
190
|
+
return typeof data === "function" ? data(args) : data;
|
|
191
|
+
};
|
|
192
|
+
/** The placements that a `meta.route` object can declare. */
|
|
193
|
+
const ROUTE_HANDLERS = new Set(["root", "local", "both"]);
|
|
194
|
+
/**
|
|
195
|
+
* Reads the placement of the generated `play.route` transition.
|
|
196
|
+
*
|
|
197
|
+
* `"root"` is the default, and it is the placement of XState: every route transition
|
|
198
|
+
* sits on the root of the machine. `"local"` moves the transition to the parent of the
|
|
199
|
+
* state, and `"both"` puts one transition in each place.
|
|
200
|
+
*
|
|
201
|
+
* The function does NOT check the form of the metadata. `normalizeRoute` runs first at
|
|
202
|
+
* every call site and throws `InvalidRouteMetadataError` on a malformed value.
|
|
203
|
+
*
|
|
204
|
+
* @param route - The route metadata: a string, an object with a `path` property, or
|
|
205
|
+
* `undefined` for a state that declares no route
|
|
206
|
+
* @param source - The `PlayError.scope` value to report for an unknown placement
|
|
207
|
+
* @returns The declared placement, and `"root"` where the metadata declares none
|
|
208
|
+
* @throws {InvalidRouteHandlerError} When the object declares a `handler` that is not
|
|
209
|
+
* `"root"`, `"local"`, or `"both"`. A typo would otherwise fall back to a placement
|
|
210
|
+
* that the author did not ask for, and it would change which states a route reaches.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* routeHandler("/dashboard"); // "root"
|
|
215
|
+
* routeHandler({ path: "/dashboard" }); // "root"
|
|
216
|
+
* routeHandler({ path: "/dashboard", handler: "local" }); // "local"
|
|
217
|
+
* routeHandler({ path: "/dashboard", handler: "both" }); // "both"
|
|
218
|
+
* routeHandler({ path: "/dashboard", handler: "locale" }); // throws
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export const routeHandler = (route, source = "formatPlayRouteTransitions") => {
|
|
222
|
+
if (typeof route !== "object" || route === null)
|
|
223
|
+
return "root";
|
|
224
|
+
const handler = route.handler;
|
|
225
|
+
if (handler === undefined)
|
|
226
|
+
return "root";
|
|
227
|
+
if (typeof handler !== "string" || !ROUTE_HANDLERS.has(handler)) {
|
|
228
|
+
throw new InvalidRouteHandlerError(handler, source);
|
|
229
|
+
}
|
|
230
|
+
return handler;
|
|
231
|
+
};
|
|
138
232
|
/**
|
|
139
233
|
* Tells you if the route path is absolute
|
|
140
234
|
*
|
|
@@ -147,7 +241,7 @@ export const normalizeRoute = (route, source = "deriveRoute") => {
|
|
|
147
241
|
*
|
|
148
242
|
* @example
|
|
149
243
|
* ```typescript
|
|
150
|
-
* import { isAbsoluteRoute } from "@xmachines/play-xstate";
|
|
244
|
+
* import { isAbsoluteRoute } from "@xmachines/play-xstate/routing";
|
|
151
245
|
*
|
|
152
246
|
* console.log(isAbsoluteRoute("/dashboard")); // true
|
|
153
247
|
* console.log(isAbsoluteRoute("settings")); // false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-route.js","sourceRoot":"","sources":["../../src/routing/derive-route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"derive-route.js","sourceRoot":"","sources":["../../src/routing/derive-route.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,13 +16,19 @@ export type RouteStateNode = {
|
|
|
16
16
|
meta?: {
|
|
17
17
|
/**
|
|
18
18
|
* The template of the URL path: the string form, for example
|
|
19
|
-
* `"/profile/:username"`, or the object form (`{ path, title }`). Both
|
|
20
|
-
* {@link RouteMetadata}.
|
|
19
|
+
* `"/profile/:username"`, or the object form (`{ path, reenter, title }`). Both
|
|
20
|
+
* match {@link RouteMetadata}. The object form declares the `reenter` flag of the
|
|
21
|
+
* generated transition, and that flag defaults to `false`.
|
|
21
22
|
*/
|
|
22
23
|
route?: RouteMetadata;
|
|
23
24
|
};
|
|
24
25
|
/** The nested child states. The function walks them for each further route declaration. */
|
|
25
26
|
states?: Record<string, RouteStateNode>;
|
|
27
|
+
/**
|
|
28
|
+
* The event handlers of this state. The function reads them where a child asks for a
|
|
29
|
+
* local `play.route` handler, so that the transitions of the user survive the merge.
|
|
30
|
+
*/
|
|
31
|
+
on?: Record<string, unknown> | undefined;
|
|
26
32
|
[key: string]: unknown;
|
|
27
33
|
};
|
|
28
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-play-route-transitions.d.ts","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"format-play-route-transitions.d.ts","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AAgB7D;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,IAAI,CAAC,EAAE;QACN;;;;;WAKG;QACH,KAAK,CAAC,EAAE,aAAa,CAAC;KACtB,CAAC;IACF,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAiHF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC7C,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,kBAAkB,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CA2L5F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assign } from "xstate";
|
|
2
|
-
import { shallowEqualExcept } from "@xmachines/play
|
|
2
|
+
import { shallowEqualExcept } from "@xmachines/play";
|
|
3
3
|
import { MissingStateIdError } from "../errors.js";
|
|
4
|
-
import { normalizeRoute } from "./derive-route.js";
|
|
4
|
+
import { normalizeRoute, routeData, routeHandler, routeReenter } from "./derive-route.js";
|
|
5
5
|
/**
|
|
6
6
|
* Reuses the previous container of the params and of the query when the new
|
|
7
7
|
* container is equal to it in a shallow comparison.
|
|
@@ -13,7 +13,73 @@ import { normalizeRoute } from "./derive-route.js";
|
|
|
13
13
|
* values, such as a popstate event to the current URL or a second send from the
|
|
14
14
|
* code, emits the view again for nothing.
|
|
15
15
|
*/
|
|
16
|
-
const keepEqualContainer = (prev, next) =>
|
|
16
|
+
const keepEqualContainer = (prev, next) => prev !== undefined && shallowEqualExcept(prev, next) ? prev : next;
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes the `play.route` entry of an `on` record into an array.
|
|
19
|
+
*
|
|
20
|
+
* A user writes one transition or an array of them, and XState accepts both forms.
|
|
21
|
+
* The merge therefore needs one form.
|
|
22
|
+
*/
|
|
23
|
+
const asTransitionArray = (value) => value === undefined ? [] : Array.isArray(value) ? value : [value];
|
|
24
|
+
/**
|
|
25
|
+
* True when the route declares a `data` field.
|
|
26
|
+
*
|
|
27
|
+
* The assigner below reads this ONE time, when it builds the action, and not on every
|
|
28
|
+
* event: the declaration of a state is static.
|
|
29
|
+
*/
|
|
30
|
+
const declaresRouteData = (route) => typeof route === "object" && route !== null && route.data !== undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Builds the assign action of a generated `play.route` transition.
|
|
33
|
+
*
|
|
34
|
+
* Every generated transition gets its OWN action object, from this one factory. The
|
|
35
|
+
* root transition and the local transition of the same state therefore hold no shared
|
|
36
|
+
* object, and the body of the assign lives in one place.
|
|
37
|
+
*
|
|
38
|
+
* A route that declares no `data` gets an assign with no `data` KEY. A key that writes
|
|
39
|
+
* the previous value back is not the same thing: `assign` puts an own property on the
|
|
40
|
+
* context for each key that it carries, so a machine that declares no `data` field
|
|
41
|
+
* received one with no value, and the `/context` projection of every view carried it.
|
|
42
|
+
*/
|
|
43
|
+
const makeRouteAssign = (routeMeta) => {
|
|
44
|
+
const params = ({ context, event }) => keepEqualContainer(context.params, event.params || {});
|
|
45
|
+
const query = ({ context, event }) => keepEqualContainer(context.query, event.query || {});
|
|
46
|
+
if (!declaresRouteData(routeMeta))
|
|
47
|
+
return assign({ params, query });
|
|
48
|
+
return assign({
|
|
49
|
+
params,
|
|
50
|
+
query,
|
|
51
|
+
// A resolver that answers `undefined` leaves the field of the context as it stands,
|
|
52
|
+
// and it therefore writes `undefined` over the data of an earlier route never.
|
|
53
|
+
data: ({ context, event }) => {
|
|
54
|
+
const previous = context.data;
|
|
55
|
+
const next = routeData(routeMeta, { context, event });
|
|
56
|
+
return next === undefined ? previous : keepEqualContainer(previous, next);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Rebuilds one state node with its local `play.route` transitions in place.
|
|
62
|
+
*
|
|
63
|
+
* The transitions of the user stay, and they come AFTER the generated ones: XState
|
|
64
|
+
* reads the candidates in their order, so a generated guard wins when it matches, and
|
|
65
|
+
* the transitions of the user are the fallback. This is the rule that the root of the
|
|
66
|
+
* machine follows too.
|
|
67
|
+
*
|
|
68
|
+
* The function writes into NO object of the caller. It returns a new node.
|
|
69
|
+
*/
|
|
70
|
+
const withLocalTransitions = (node, states, transitions) => {
|
|
71
|
+
if (transitions.length === 0)
|
|
72
|
+
return { ...node, states };
|
|
73
|
+
const existingOn = node.on ?? {};
|
|
74
|
+
return {
|
|
75
|
+
...node,
|
|
76
|
+
states,
|
|
77
|
+
on: {
|
|
78
|
+
...existingOn,
|
|
79
|
+
"play.route": [...transitions, ...asTransitionArray(existingOn["play.route"])],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
};
|
|
17
83
|
/**
|
|
18
84
|
* Makes the play.route transitions from the declarative route configs
|
|
19
85
|
*
|
|
@@ -49,7 +115,14 @@ const keepEqualContainer = (prev, next) => (prev !== undefined && shallowEqualEx
|
|
|
49
115
|
export function formatPlayRouteTransitions(machineConfig) {
|
|
50
116
|
const routeTransitions = [];
|
|
51
117
|
const collectRoutes = (states, parentPath = "") => {
|
|
52
|
-
|
|
118
|
+
const localTransitions = [];
|
|
119
|
+
let changed = false;
|
|
120
|
+
// The walk collects PAIRS, and `Object.fromEntries` builds the record at the end.
|
|
121
|
+
// A write through `nextStates[key]` would reach the `__proto__` setter of
|
|
122
|
+
// `Object.prototype` for a state whose key is `"__proto__"`, and it would set the
|
|
123
|
+
// prototype of the record instead of adding a state to it. `fromEntries` defines
|
|
124
|
+
// an own property for every key, so no key of a config is special.
|
|
125
|
+
const nextEntries = Object.entries(states).map(([key, stateConfig]) => {
|
|
53
126
|
const node = stateConfig;
|
|
54
127
|
// Build the complete path of the keys, from the root, for the target of the
|
|
55
128
|
// transition. An XState target uses the hierarchy of the state keys, and not the
|
|
@@ -59,80 +132,134 @@ export function formatPlayRouteTransitions(machineConfig) {
|
|
|
59
132
|
// InvalidRouteMetadataError. It then normalizes the value into the string of the
|
|
60
133
|
// path. An empty path marks the state as a state without a route, in the string form
|
|
61
134
|
// ("") and also in the object form ({ path: "" }).
|
|
62
|
-
const
|
|
135
|
+
const routeMeta = node.meta?.route;
|
|
136
|
+
const routePath = routeMeta === undefined
|
|
63
137
|
? ""
|
|
64
|
-
: normalizeRoute(
|
|
138
|
+
: normalizeRoute(routeMeta, "formatPlayRouteTransitions");
|
|
139
|
+
// Check the placement for EVERY declared route, and not only for one that
|
|
140
|
+
// produces a transition. A state with an empty path generates none, and a typo
|
|
141
|
+
// in its `handler` would otherwise wait silently until somebody gives the state
|
|
142
|
+
// a path.
|
|
143
|
+
const placement = routeHandler(routeMeta);
|
|
65
144
|
if (routePath && !node.id) {
|
|
66
145
|
throw new MissingStateIdError(key, routePath);
|
|
67
146
|
}
|
|
68
147
|
if (routePath && node.id) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
148
|
+
// The declaration of the state decides the flag, and the default is `false`,
|
|
149
|
+
// which is the default of XState. The flag spares the DOMAIN of the
|
|
150
|
+
// transition: under the root placement it spares the root alone, and each
|
|
151
|
+
// ancestor between the root and the target still runs its exit and its entry
|
|
152
|
+
// actions. `handler` is the field that spares those.
|
|
153
|
+
const reenter = routeReenter(routeMeta);
|
|
154
|
+
// A parent path of "" means that the parent IS the root. The root transition of
|
|
155
|
+
// such a state already targets `.${key}`, so it IS the local transition, and
|
|
156
|
+
// every placement therefore collapses to the root transition.
|
|
157
|
+
const parentIsRoot = parentPath === "";
|
|
158
|
+
const wantsRoot = parentIsRoot || placement === "root" || placement === "both";
|
|
159
|
+
const wantsLocal = !parentIsRoot && (placement === "local" || placement === "both");
|
|
160
|
+
// The ROOT transition. XState installs every route transition on the root, and
|
|
161
|
+
// this function keeps that placement as its default: a route from ANY state
|
|
162
|
+
// therefore reaches this state.
|
|
163
|
+
if (wantsRoot) {
|
|
164
|
+
routeTransitions.push({
|
|
165
|
+
target: `.${statePath}`,
|
|
166
|
+
guard: ({ event }) => event.to === `#${node.id}`,
|
|
167
|
+
reenter,
|
|
168
|
+
actions: makeRouteAssign(routeMeta),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// The LOCAL transition. It sits on the PARENT of this state, and it targets
|
|
172
|
+
// this state relatively. XState offers the transitions of the deepest active
|
|
173
|
+
// state node first, so this transition answers the event while the parent is
|
|
174
|
+
// active, and the parent therefore runs its exit and its entry actions NOT
|
|
175
|
+
// again.
|
|
176
|
+
//
|
|
177
|
+
// Under `"local"` this is the ONLY transition of the state, so a route that
|
|
178
|
+
// arrives while the parent is inactive matches nothing and the actor does not
|
|
179
|
+
// move. That is the declared intent of `"local"`: it scopes the route.
|
|
180
|
+
if (wantsLocal) {
|
|
181
|
+
localTransitions.push({
|
|
182
|
+
target: `.${key}`,
|
|
183
|
+
guard: ({ event }) => event.to === `#${node.id}`,
|
|
184
|
+
reenter,
|
|
185
|
+
actions: makeRouteAssign(routeMeta),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
79
188
|
}
|
|
189
|
+
let nextNode = stateConfig;
|
|
80
190
|
if (node.states) {
|
|
81
|
-
collectRoutes(node.states, statePath);
|
|
191
|
+
const child = collectRoutes(node.states, statePath);
|
|
192
|
+
if (child.changed || child.localTransitions.length > 0) {
|
|
193
|
+
// Rebuild this node, and do NOT write into the config of the caller. The
|
|
194
|
+
// function returns a new config, and the original must stay untouched.
|
|
195
|
+
nextNode = withLocalTransitions(node, child.states, child.localTransitions);
|
|
196
|
+
changed = true;
|
|
197
|
+
}
|
|
82
198
|
}
|
|
199
|
+
return [key, nextNode];
|
|
83
200
|
});
|
|
201
|
+
return { states: Object.fromEntries(nextEntries), localTransitions, changed };
|
|
84
202
|
};
|
|
85
203
|
const machineStates = machineConfig.states;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
204
|
+
// `states` comes back rebuilt where a descendant asked for a local handler, and it
|
|
205
|
+
// comes back as the original record where none did. The walk returns no local
|
|
206
|
+
// transition for the top level: the parent of a top-level state IS the root, and the
|
|
207
|
+
// root transition of such a state is already local to its parent.
|
|
208
|
+
const walk = machineStates ? collectRoutes(machineStates) : undefined;
|
|
89
209
|
// The ROOT of the machine can declare a route of its own, which a chart does when
|
|
90
210
|
// its whole document owns a path prefix, for example `/doc` with `/doc/a` under it.
|
|
91
211
|
// `collectRoutes` walks `states` only, so the root got no transition, and a URL for
|
|
92
212
|
// the root moved the machine nowhere: a press on BACK to `/doc` left the actor on
|
|
93
213
|
// the child it already held, and the URL and the actor diverged.
|
|
94
214
|
//
|
|
95
|
-
// The transition targets the root by its
|
|
96
|
-
//
|
|
97
|
-
// root
|
|
215
|
+
// The transition targets the root by its ID. XState enters the `initial` child of
|
|
216
|
+
// an ID target, which is the state that a URL for the root means. The `reenter`
|
|
217
|
+
// flag does NOT decide that: a route to the root lands on the initial child of the
|
|
218
|
+
// root under `false` and under `true`. The flag decides only whether the root runs
|
|
219
|
+
// its own `exit` and `entry` actions again. The root therefore reads the flag from
|
|
220
|
+
// its `meta.route` like every other state, and it defaults to `false`.
|
|
98
221
|
const rootNode = machineConfig;
|
|
99
|
-
const
|
|
222
|
+
const rootRouteMeta = rootNode.meta?.route;
|
|
223
|
+
const rootRoutePath = rootRouteMeta === undefined
|
|
100
224
|
? ""
|
|
101
|
-
: normalizeRoute(
|
|
225
|
+
: normalizeRoute(rootRouteMeta, "formatPlayRouteTransitions");
|
|
226
|
+
// The placement of the ROOT has no meaning, because the root has no parent to hold a
|
|
227
|
+
// local transition. A value that the routing layer does not know must still fail
|
|
228
|
+
// here, so that one typo behaves the same wherever an author writes it.
|
|
229
|
+
routeHandler(rootRouteMeta);
|
|
102
230
|
if (rootRoutePath) {
|
|
103
231
|
if (!rootNode.id)
|
|
104
232
|
throw new MissingStateIdError("(the root of the machine)", rootRoutePath);
|
|
105
233
|
routeTransitions.push({
|
|
106
234
|
target: `#${rootNode.id}`,
|
|
107
235
|
guard: ({ event }) => event.to === `#${rootNode.id}`,
|
|
108
|
-
reenter:
|
|
109
|
-
actions:
|
|
110
|
-
params: ({ context, event }) => keepEqualContainer(context.params, event.params || {}),
|
|
111
|
-
query: ({ context, event }) => keepEqualContainer(context.query, event.query || {}),
|
|
112
|
-
}),
|
|
236
|
+
reenter: routeReenter(rootRouteMeta),
|
|
237
|
+
actions: makeRouteAssign(rootRouteMeta),
|
|
113
238
|
});
|
|
114
239
|
}
|
|
240
|
+
const rebuiltStates = walk?.changed === true;
|
|
241
|
+
// A machine whose every routable state declares `handler: "local"` produces NO root
|
|
242
|
+
// transition, and its transitions live on the rebuilt states alone. The rebuilt
|
|
243
|
+
// states must therefore survive on their own, and not only beside a root
|
|
244
|
+
// transition.
|
|
245
|
+
if (routeTransitions.length === 0 && !rebuiltStates) {
|
|
246
|
+
return machineConfig;
|
|
247
|
+
}
|
|
248
|
+
const next = {
|
|
249
|
+
...machineConfig,
|
|
250
|
+
...(rebuiltStates ? { states: walk?.states } : {}),
|
|
251
|
+
};
|
|
115
252
|
if (routeTransitions.length > 0) {
|
|
116
253
|
const existingOn = machineConfig.on || {};
|
|
117
254
|
// Keep each play.route transition of the user, for example a 404 fallback that a
|
|
118
255
|
// person wrote, and append those transitions AFTER the generated ones: XState
|
|
119
256
|
// evaluates the candidate transitions in their order. Therefore a generated guard
|
|
120
257
|
// wins when it matches, and the transitions of the user are the fallback.
|
|
121
|
-
|
|
122
|
-
const normalizedUserTransitions = userRouteTransitions === undefined
|
|
123
|
-
? []
|
|
124
|
-
: Array.isArray(userRouteTransitions)
|
|
125
|
-
? userRouteTransitions
|
|
126
|
-
: [userRouteTransitions];
|
|
127
|
-
const updatedOn = {
|
|
258
|
+
next["on"] = {
|
|
128
259
|
...existingOn,
|
|
129
|
-
"play.route": [...routeTransitions, ...
|
|
130
|
-
};
|
|
131
|
-
return {
|
|
132
|
-
...machineConfig,
|
|
133
|
-
on: updatedOn,
|
|
260
|
+
"play.route": [...routeTransitions, ...asTransitionArray(existingOn["play.route"])],
|
|
134
261
|
};
|
|
135
262
|
}
|
|
136
|
-
return
|
|
263
|
+
return next;
|
|
137
264
|
}
|
|
138
265
|
//# sourceMappingURL=format-play-route-transitions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG1F;;;;;;;;;;GAUG;AACH,MAAM,kBAAkB,GAAG,CAAoC,IAAmB,EAAE,IAAO,EAAK,EAAE,CACjG,IAAI,KAAK,SAAS,IAAI,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAmCpE;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAa,EAAE,CACvD,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAKnE;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAAgC,EAAW,EAAE,CACvE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAAqB,CAAC,IAAI,KAAK,SAAS,CAAC;AAE1F;;;;;;;;;;;GAWG;AACH,MAAM,eAAe,GAAG,CAAC,SAAoC,EAAE,EAAE;IAChE,MAAM,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAmB,EAAE,EAAE,CACtD,kBAAkB,CAChB,OAA+C,CAAC,MAAM,EACvD,KAAK,CAAC,MAAM,IAAI,EAAE,CAClB,CAAC;IACH,MAAM,KAAK,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAmB,EAAE,EAAE,CACrD,kBAAkB,CAChB,OAA8C,CAAC,KAAK,EACrD,KAAK,CAAC,KAAK,IAAI,EAAE,CACjB,CAAC;IAEH,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpE,OAAO,MAAM,CAAC;QACb,MAAM;QACN,KAAK;QACL,oFAAoF;QACpF,+EAA+E;QAC/E,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAmB,EAAE,EAAE;YAC7C,MAAM,QAAQ,GAAI,OAAgC,CAAC,IAAI,CAAC;YACxD,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3E,CAAC;KACD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,oBAAoB,GAAG,CAC5B,IAAoB,EACpB,MAA+B,EAC/B,WAA8B,EACpB,EAAE;IACZ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC;IAEzD,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO;QACN,GAAG,IAAI;QACP,MAAM;QACN,EAAE,EAAE;YACH,GAAG,UAAU;YACb,YAAY,EAAE,CAAC,GAAG,WAAW,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;SAC9E;KACD,CAAC;AACH,CAAC,CAAC;AA2CF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,0BAA0B,CAA+B,aAAgB;IACxF,MAAM,gBAAgB,GAAsB,EAAE,CAAC;IAgB/C,MAAM,aAAa,GAAG,CAAC,MAA+B,EAAE,UAAU,GAAG,EAAE,EAAc,EAAE;QACtF,MAAM,gBAAgB,GAAsB,EAAE,CAAC;QAC/C,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,kFAAkF;QAClF,0EAA0E;QAC1E,kFAAkF;QAClF,iFAAiF;QACjF,mEAAmE;QACnE,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,EAAqB,EAAE;YACxF,MAAM,IAAI,GAAG,WAA6B,CAAC;YAC3C,4EAA4E;YAC5E,iFAAiF;YACjF,gBAAgB;YAChB,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAC5D,qFAAqF;YACrF,iFAAiF;YACjF,qFAAqF;YACrF,mDAAmD;YACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;YACnC,MAAM,SAAS,GACd,SAAS,KAAK,SAAS;gBACtB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC;YAE5D,0EAA0E;YAC1E,+EAA+E;YAC/E,gFAAgF;YAChF,UAAU;YACV,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YAE1C,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,IAAI,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/C,CAAC;YAED,IAAI,SAAS,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBAC1B,6EAA6E;gBAC7E,oEAAoE;gBACpE,0EAA0E;gBAC1E,6EAA6E;gBAC7E,qDAAqD;gBACrD,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;gBAExC,gFAAgF;gBAChF,6EAA6E;gBAC7E,8DAA8D;gBAC9D,MAAM,YAAY,GAAG,UAAU,KAAK,EAAE,CAAC;gBACvC,MAAM,SAAS,GAAG,YAAY,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,MAAM,CAAC;gBAC/E,MAAM,UAAU,GAAG,CAAC,YAAY,IAAI,CAAC,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC;gBAEpF,+EAA+E;gBAC/E,4EAA4E;gBAC5E,gCAAgC;gBAChC,IAAI,SAAS,EAAE,CAAC;oBACf,gBAAgB,CAAC,IAAI,CAAC;wBACrB,MAAM,EAAE,IAAI,SAAS,EAAE;wBACvB,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,EAAE,EAAE;wBAChD,OAAO;wBACP,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC;qBACnC,CAAC,CAAC;gBACJ,CAAC;gBAED,4EAA4E;gBAC5E,6EAA6E;gBAC7E,6EAA6E;gBAC7E,2EAA2E;gBAC3E,SAAS;gBACT,EAAE;gBACF,4EAA4E;gBAC5E,8EAA8E;gBAC9E,uEAAuE;gBACvE,IAAI,UAAU,EAAE,CAAC;oBAChB,gBAAgB,CAAC,IAAI,CAAC;wBACrB,MAAM,EAAE,IAAI,GAAG,EAAE;wBACjB,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,EAAE,EAAE;wBAChD,OAAO;wBACP,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC;qBACnC,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,IAAI,QAAQ,GAAY,WAAW,CAAC;YAEpC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBACpD,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxD,yEAAyE;oBACzE,uEAAuE;oBACvE,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;oBAC5E,OAAO,GAAG,IAAI,CAAC;gBAChB,CAAC;YACF,CAAC;YAED,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;IAC/E,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC;IAC3C,mFAAmF;IACnF,8EAA8E;IAC9E,qFAAqF;IACrF,kEAAkE;IAClE,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtE,kFAAkF;IAClF,oFAAoF;IACpF,oFAAoF;IACpF,kFAAkF;IAClF,iEAAiE;IACjE,EAAE;IACF,kFAAkF;IAClF,gFAAgF;IAChF,mFAAmF;IACnF,mFAAmF;IACnF,mFAAmF;IACnF,uEAAuE;IACvE,MAAM,QAAQ,GAAG,aAA+B,CAAC;IACjD,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAC3C,MAAM,aAAa,GAClB,aAAa,KAAK,SAAS;QAC1B,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,cAAc,CAAC,aAAa,EAAE,4BAA4B,CAAC,CAAC;IAEhE,qFAAqF;IACrF,iFAAiF;IACjF,wEAAwE;IACxE,YAAY,CAAC,aAAa,CAAC,CAAC;IAE5B,IAAI,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,mBAAmB,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;QAE5F,gBAAgB,CAAC,IAAI,CAAC;YACrB,MAAM,EAAE,IAAI,QAAQ,CAAC,EAAE,EAAE;YACzB,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE,EAAE;YACpD,OAAO,EAAE,YAAY,CAAC,aAAa,CAAC;YACpC,OAAO,EAAE,eAAe,CAAC,aAAa,CAAC;SACvC,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7C,oFAAoF;IACpF,gFAAgF;IAChF,yEAAyE;IACzE,cAAc;IACd,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACrD,OAAO,aAAa,CAAC;IACtB,CAAC;IAED,MAAM,IAAI,GAA4B;QACrC,GAAG,aAAa;QAChB,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;IAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC;QAE1C,iFAAiF;QACjF,8EAA8E;QAC9E,kFAAkF;QAClF,0EAA0E;QAC1E,IAAI,CAAC,IAAI,CAAC,GAAG;YACZ,GAAG,UAAU;YACb,YAAY,EAAE,CAAC,GAAG,gBAAgB,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;SACnF,CAAC;IACH,CAAC;IAED,OAAO,IAAS,CAAC;AAClB,CAAC"}
|
package/dist/routing/index.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export { deriveInitialRoute } from "./derive-initial-route.js";
|
|
|
12
12
|
export { buildRouteUrl } from "./build-url.js";
|
|
13
13
|
export { formatPlayRouteTransitions } from "./format-play-route-transitions.js";
|
|
14
14
|
export type { RouteMachineConfig, RouteStateNode } from "./format-play-route-transitions.js";
|
|
15
|
-
export type { RouteContext, RouteObject, RouteMetadata } from "./types.js";
|
|
15
|
+
export type { RouteContext, RouteObject, RouteMetadata, RouteData, RouteDataResolver, } from "./types.js";
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAC7F,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAC7F,YAAY,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,GACjB,MAAM,YAAY,CAAC"}
|