@xmachines/play-xstate 3.0.0 → 5.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 +190 -68
- package/dist/capabilities.d.ts +93 -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 +64 -23
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +93 -31
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +73 -137
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +108 -254
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/build-url.d.ts +8 -1
- package/dist/routing/build-url.d.ts.map +1 -1
- package/dist/routing/build-url.js +34 -54
- package/dist/routing/build-url.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +12 -38
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +24 -82
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts +2 -1
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +13 -2
- 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 +175 -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 +20 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +7 -6
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +7 -6
- 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 +140 -0
- package/dist/with-routing.js.map +1 -0
- package/dist/with-view.d.ts +57 -0
- package/dist/with-view.d.ts.map +1 -0
- package/dist/with-view.js +158 -0
- package/dist/with-view.js.map +1 -0
- package/package.json +40 -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
|
@@ -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,78 @@ 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
|
+
* The `params` and the `query` of the event, each beside the container that the context
|
|
33
|
+
* holds already. Neither one reads the metadata of the route, so both stand here rather
|
|
34
|
+
* than inside the factory, where a call rebuilt them for every generated transition.
|
|
35
|
+
*/
|
|
36
|
+
const assignParams = ({ context, event }) => keepEqualContainer(context.params, event.params || {});
|
|
37
|
+
const assignQuery = ({ context, event }) => keepEqualContainer(context.query, event.query || {});
|
|
38
|
+
/**
|
|
39
|
+
* Builds the assign action of a generated `play.route` transition.
|
|
40
|
+
*
|
|
41
|
+
* Every generated transition gets its OWN action object, from this one factory. The
|
|
42
|
+
* root transition and the local transition of the same state therefore hold no shared
|
|
43
|
+
* object, and the body of the assign lives in one place.
|
|
44
|
+
*
|
|
45
|
+
* A route that declares no `data` gets an assign with no `data` KEY. A key that writes
|
|
46
|
+
* the previous value back is not the same thing: `assign` puts an own property on the
|
|
47
|
+
* context for each key that it carries, so a machine that declares no `data` field
|
|
48
|
+
* received one with no value, and the `/context` projection of every view carried it.
|
|
49
|
+
*/
|
|
50
|
+
const makeRouteAssign = (routeMeta) => {
|
|
51
|
+
if (!declaresRouteData(routeMeta))
|
|
52
|
+
return assign({ params: assignParams, query: assignQuery });
|
|
53
|
+
return assign({
|
|
54
|
+
params: assignParams,
|
|
55
|
+
query: assignQuery,
|
|
56
|
+
// A resolver that answers `undefined` leaves the field of the context as it stands,
|
|
57
|
+
// and it therefore writes `undefined` over the data of an earlier route never.
|
|
58
|
+
data: ({ context, event }) => {
|
|
59
|
+
const previous = context.data;
|
|
60
|
+
const next = routeData(routeMeta, { context, event });
|
|
61
|
+
return next === undefined ? previous : keepEqualContainer(previous, next);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Rebuilds one state node with its local `play.route` transitions in place.
|
|
67
|
+
*
|
|
68
|
+
* The transitions of the user stay, and they come AFTER the generated ones: XState
|
|
69
|
+
* reads the candidates in their order, so a generated guard wins when it matches, and
|
|
70
|
+
* the transitions of the user are the fallback. This is the rule that the root of the
|
|
71
|
+
* machine follows too.
|
|
72
|
+
*
|
|
73
|
+
* The function writes into NO object of the caller. It returns a new node.
|
|
74
|
+
*/
|
|
75
|
+
const withLocalTransitions = (node, states, transitions) => {
|
|
76
|
+
if (transitions.length === 0)
|
|
77
|
+
return { ...node, states };
|
|
78
|
+
const existingOn = node.on ?? {};
|
|
79
|
+
return {
|
|
80
|
+
...node,
|
|
81
|
+
states,
|
|
82
|
+
on: {
|
|
83
|
+
...existingOn,
|
|
84
|
+
"play.route": [...transitions, ...asTransitionArray(existingOn["play.route"])],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
};
|
|
17
88
|
/**
|
|
18
89
|
* Makes the play.route transitions from the declarative route configs
|
|
19
90
|
*
|
|
@@ -49,7 +120,14 @@ const keepEqualContainer = (prev, next) => (prev !== undefined && shallowEqualEx
|
|
|
49
120
|
export function formatPlayRouteTransitions(machineConfig) {
|
|
50
121
|
const routeTransitions = [];
|
|
51
122
|
const collectRoutes = (states, parentPath = "") => {
|
|
52
|
-
|
|
123
|
+
const localTransitions = [];
|
|
124
|
+
let changed = false;
|
|
125
|
+
// The walk collects PAIRS, and `Object.fromEntries` builds the record at the end.
|
|
126
|
+
// A write through `nextStates[key]` would reach the `__proto__` setter of
|
|
127
|
+
// `Object.prototype` for a state whose key is `"__proto__"`, and it would set the
|
|
128
|
+
// prototype of the record instead of adding a state to it. `fromEntries` defines
|
|
129
|
+
// an own property for every key, so no key of a config is special.
|
|
130
|
+
const nextEntries = Object.entries(states).map(([key, stateConfig]) => {
|
|
53
131
|
const node = stateConfig;
|
|
54
132
|
// Build the complete path of the keys, from the root, for the target of the
|
|
55
133
|
// transition. An XState target uses the hierarchy of the state keys, and not the
|
|
@@ -59,80 +137,134 @@ export function formatPlayRouteTransitions(machineConfig) {
|
|
|
59
137
|
// InvalidRouteMetadataError. It then normalizes the value into the string of the
|
|
60
138
|
// path. An empty path marks the state as a state without a route, in the string form
|
|
61
139
|
// ("") and also in the object form ({ path: "" }).
|
|
62
|
-
const
|
|
140
|
+
const routeMeta = node.meta?.route;
|
|
141
|
+
const routePath = routeMeta === undefined
|
|
63
142
|
? ""
|
|
64
|
-
: normalizeRoute(
|
|
143
|
+
: normalizeRoute(routeMeta, "formatPlayRouteTransitions");
|
|
144
|
+
// Check the placement for EVERY declared route, and not only for one that
|
|
145
|
+
// produces a transition. A state with an empty path generates none, and a typo
|
|
146
|
+
// in its `handler` would otherwise wait silently until somebody gives the state
|
|
147
|
+
// a path.
|
|
148
|
+
const placement = routeHandler(routeMeta);
|
|
65
149
|
if (routePath && !node.id) {
|
|
66
150
|
throw new MissingStateIdError(key, routePath);
|
|
67
151
|
}
|
|
68
152
|
if (routePath && node.id) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
153
|
+
// The declaration of the state decides the flag, and the default is `false`,
|
|
154
|
+
// which is the default of XState. The flag spares the DOMAIN of the
|
|
155
|
+
// transition: under the root placement it spares the root alone, and each
|
|
156
|
+
// ancestor between the root and the target still runs its exit and its entry
|
|
157
|
+
// actions. `handler` is the field that spares those.
|
|
158
|
+
const reenter = routeReenter(routeMeta);
|
|
159
|
+
// A parent path of "" means that the parent IS the root. The root transition of
|
|
160
|
+
// such a state already targets `.${key}`, so it IS the local transition, and
|
|
161
|
+
// every placement therefore collapses to the root transition.
|
|
162
|
+
const parentIsRoot = parentPath === "";
|
|
163
|
+
const wantsRoot = parentIsRoot || placement === "root" || placement === "both";
|
|
164
|
+
const wantsLocal = !parentIsRoot && (placement === "local" || placement === "both");
|
|
165
|
+
// The ROOT transition. XState installs every route transition on the root, and
|
|
166
|
+
// this function keeps that placement as its default: a route from ANY state
|
|
167
|
+
// therefore reaches this state.
|
|
168
|
+
if (wantsRoot) {
|
|
169
|
+
routeTransitions.push({
|
|
170
|
+
target: `.${statePath}`,
|
|
171
|
+
guard: ({ event }) => event.to === `#${node.id}`,
|
|
172
|
+
reenter,
|
|
173
|
+
actions: makeRouteAssign(routeMeta),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// The LOCAL transition. It sits on the PARENT of this state, and it targets
|
|
177
|
+
// this state relatively. XState offers the transitions of the deepest active
|
|
178
|
+
// state node first, so this transition answers the event while the parent is
|
|
179
|
+
// active, and the parent therefore runs its exit and its entry actions NOT
|
|
180
|
+
// again.
|
|
181
|
+
//
|
|
182
|
+
// Under `"local"` this is the ONLY transition of the state, so a route that
|
|
183
|
+
// arrives while the parent is inactive matches nothing and the actor does not
|
|
184
|
+
// move. That is the declared intent of `"local"`: it scopes the route.
|
|
185
|
+
if (wantsLocal) {
|
|
186
|
+
localTransitions.push({
|
|
187
|
+
target: `.${key}`,
|
|
188
|
+
guard: ({ event }) => event.to === `#${node.id}`,
|
|
189
|
+
reenter,
|
|
190
|
+
actions: makeRouteAssign(routeMeta),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
79
193
|
}
|
|
194
|
+
let nextNode = stateConfig;
|
|
80
195
|
if (node.states) {
|
|
81
|
-
collectRoutes(node.states, statePath);
|
|
196
|
+
const child = collectRoutes(node.states, statePath);
|
|
197
|
+
if (child.changed || child.localTransitions.length > 0) {
|
|
198
|
+
// Rebuild this node, and do NOT write into the config of the caller. The
|
|
199
|
+
// function returns a new config, and the original must stay untouched.
|
|
200
|
+
nextNode = withLocalTransitions(node, child.states, child.localTransitions);
|
|
201
|
+
changed = true;
|
|
202
|
+
}
|
|
82
203
|
}
|
|
204
|
+
return [key, nextNode];
|
|
83
205
|
});
|
|
206
|
+
return { states: Object.fromEntries(nextEntries), localTransitions, changed };
|
|
84
207
|
};
|
|
85
208
|
const machineStates = machineConfig.states;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
209
|
+
// `states` comes back rebuilt where a descendant asked for a local handler, and it
|
|
210
|
+
// comes back as the original record where none did. The walk returns no local
|
|
211
|
+
// transition for the top level: the parent of a top-level state IS the root, and the
|
|
212
|
+
// root transition of such a state is already local to its parent.
|
|
213
|
+
const walk = machineStates ? collectRoutes(machineStates) : undefined;
|
|
89
214
|
// The ROOT of the machine can declare a route of its own, which a chart does when
|
|
90
215
|
// its whole document owns a path prefix, for example `/doc` with `/doc/a` under it.
|
|
91
216
|
// `collectRoutes` walks `states` only, so the root got no transition, and a URL for
|
|
92
217
|
// the root moved the machine nowhere: a press on BACK to `/doc` left the actor on
|
|
93
218
|
// the child it already held, and the URL and the actor diverged.
|
|
94
219
|
//
|
|
95
|
-
// The transition targets the root by its
|
|
96
|
-
//
|
|
97
|
-
// root
|
|
220
|
+
// The transition targets the root by its ID. XState enters the `initial` child of
|
|
221
|
+
// an ID target, which is the state that a URL for the root means. The `reenter`
|
|
222
|
+
// flag does NOT decide that: a route to the root lands on the initial child of the
|
|
223
|
+
// root under `false` and under `true`. The flag decides only whether the root runs
|
|
224
|
+
// its own `exit` and `entry` actions again. The root therefore reads the flag from
|
|
225
|
+
// its `meta.route` like every other state, and it defaults to `false`.
|
|
98
226
|
const rootNode = machineConfig;
|
|
99
|
-
const
|
|
227
|
+
const rootRouteMeta = rootNode.meta?.route;
|
|
228
|
+
const rootRoutePath = rootRouteMeta === undefined
|
|
100
229
|
? ""
|
|
101
|
-
: normalizeRoute(
|
|
230
|
+
: normalizeRoute(rootRouteMeta, "formatPlayRouteTransitions");
|
|
231
|
+
// The placement of the ROOT has no meaning, because the root has no parent to hold a
|
|
232
|
+
// local transition. A value that the routing layer does not know must still fail
|
|
233
|
+
// here, so that one typo behaves the same wherever an author writes it.
|
|
234
|
+
routeHandler(rootRouteMeta);
|
|
102
235
|
if (rootRoutePath) {
|
|
103
236
|
if (!rootNode.id)
|
|
104
237
|
throw new MissingStateIdError("(the root of the machine)", rootRoutePath);
|
|
105
238
|
routeTransitions.push({
|
|
106
239
|
target: `#${rootNode.id}`,
|
|
107
240
|
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
|
-
}),
|
|
241
|
+
reenter: routeReenter(rootRouteMeta),
|
|
242
|
+
actions: makeRouteAssign(rootRouteMeta),
|
|
113
243
|
});
|
|
114
244
|
}
|
|
245
|
+
const rebuiltStates = walk?.changed === true;
|
|
246
|
+
// A machine whose every routable state declares `handler: "local"` produces NO root
|
|
247
|
+
// transition, and its transitions live on the rebuilt states alone. The rebuilt
|
|
248
|
+
// states must therefore survive on their own, and not only beside a root
|
|
249
|
+
// transition.
|
|
250
|
+
if (routeTransitions.length === 0 && !rebuiltStates) {
|
|
251
|
+
return machineConfig;
|
|
252
|
+
}
|
|
253
|
+
const next = {
|
|
254
|
+
...machineConfig,
|
|
255
|
+
...(rebuiltStates ? { states: walk?.states } : {}),
|
|
256
|
+
};
|
|
115
257
|
if (routeTransitions.length > 0) {
|
|
116
258
|
const existingOn = machineConfig.on || {};
|
|
117
259
|
// Keep each play.route transition of the user, for example a 404 fallback that a
|
|
118
260
|
// person wrote, and append those transitions AFTER the generated ones: XState
|
|
119
261
|
// evaluates the candidate transitions in their order. Therefore a generated guard
|
|
120
262
|
// 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 = {
|
|
263
|
+
next["on"] = {
|
|
128
264
|
...existingOn,
|
|
129
|
-
"play.route": [...routeTransitions, ...
|
|
130
|
-
};
|
|
131
|
-
return {
|
|
132
|
-
...machineConfig,
|
|
133
|
-
on: updatedOn,
|
|
265
|
+
"play.route": [...routeTransitions, ...asTransitionArray(existingOn["play.route"])],
|
|
134
266
|
};
|
|
135
267
|
}
|
|
136
|
-
return
|
|
268
|
+
return next;
|
|
137
269
|
}
|
|
138
270
|
//# 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":"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"}
|
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"}
|
package/dist/routing/types.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `RouteObject` and `RouteMetadata` have ONE definition, and it lives in
|
|
3
|
+
* `@xmachines/play-router`. That package owns the routing protocol, and this package
|
|
4
|
+
* consumes it. A second definition here would be a copy that drifts: a field added to
|
|
5
|
+
* one of them would leave the other behind, and nothing would fail.
|
|
6
|
+
*
|
|
7
|
+
* The re-export keeps the import path of every consumer of this package unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export type { RouteObject, RouteMetadata, RouteData, RouteDataResolver, } from "@xmachines/play-router";
|
|
6
10
|
/**
|
|
7
11
|
* The context of the route construction, from the machine context.
|
|
8
12
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EACX,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,GACjB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read of the `meta` of the active states, which BOTH capabilities share.
|
|
3
|
+
*
|
|
4
|
+
* `deriveCurrentRoute` folds this record into a URL, and `deriveCurrentView` folds the
|
|
5
|
+
* same record into a view spec. The two therefore cannot move apart on the selection of
|
|
6
|
+
* the branch, and they cannot move apart on their tolerance of a degenerate snapshot.
|
|
7
|
+
*
|
|
8
|
+
* It lives in its own module, and no longer beside the route derivation, because it
|
|
9
|
+
* belongs to neither capability. `@xmachines/play-xstate/view` imported it from
|
|
10
|
+
* `routing/derive-current-route.ts`, and that module reads `deriveRoute`, which names
|
|
11
|
+
* `@xmachines/play-router`. A view-only application therefore loaded the whole route
|
|
12
|
+
* derivation, and the OPTIONAL peer of the routing reached the runtime graph of the view
|
|
13
|
+
* entry point.
|
|
14
|
+
*/
|
|
15
|
+
import type { AnyMachineSnapshot } from "xstate";
|
|
16
|
+
/**
|
|
17
|
+
* Collects the `meta` object of the active state nodes of a SINGLE branch, from the
|
|
18
|
+
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
19
|
+
* ancestors first. {@link deriveRoute} folds this shape.
|
|
20
|
+
*
|
|
21
|
+
* `snapshot.getMeta()` returns a FLAT record of the meta object of every active
|
|
22
|
+
* state. For a machine that is not parallel, that record is one chain of ancestors
|
|
23
|
+
* already. For a PARALLEL machine, it mixes the entries of every active region. A
|
|
24
|
+
* blind fold therefore joins a relative route of one region to an absolute route of
|
|
25
|
+
* a sibling region, and the URL belongs to the tree of neither region. The flat
|
|
26
|
+
* record also cannot go back into a hierarchy: when a state declares an explicit
|
|
27
|
+
* `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
|
|
28
|
+
* the meta keys are those ids, and they carry no information about the ancestry.
|
|
29
|
+
*
|
|
30
|
+
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
31
|
+
* the active states by the state key, against the node tree of the machine. It
|
|
32
|
+
* follows the FIRST active child at each level. This gives one deterministic branch,
|
|
33
|
+
* which matches the historical behavior of "the first that it finds" for a parallel
|
|
34
|
+
* machine. It also works with an explicit id, because each node carries its own `id`
|
|
35
|
+
* and its own `meta`.
|
|
36
|
+
*
|
|
37
|
+
* The function returns `null` when the snapshot exposes no machine and no value to
|
|
38
|
+
* walk. This is a defensive measure, because a real XState snapshot always exposes
|
|
39
|
+
* them. The caller then uses `getMeta()`, as before.
|
|
40
|
+
*/
|
|
41
|
+
export declare const firstActiveBranchMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
42
|
+
/**
|
|
43
|
+
* Resolves the meta record that the route derivation and the view derivation fold:
|
|
44
|
+
* the single active branch that {@link firstActiveBranchMeta} walks, which is
|
|
45
|
+
* correct for a parallel machine and for an explicit id, or the flat `getMeta()`
|
|
46
|
+
* record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
|
|
47
|
+
* `deriveCurrentView` share this function. Therefore the two sides cannot move apart
|
|
48
|
+
* on the selection of the branch, and they cannot move apart on their tolerance of a
|
|
49
|
+
* degenerate snapshot.
|
|
50
|
+
*/
|
|
51
|
+
export declare const activeStateMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
52
|
+
//# sourceMappingURL=state-meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-meta.d.ts","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,qBAAqB,GACjC,UAAU,kBAAkB,KAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAqC5B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAMxF,CAAC"}
|