@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
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collects the `meta` object of the active state nodes of a SINGLE branch, from the
|
|
3
|
+
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
4
|
+
* ancestors first. {@link deriveRoute} folds this shape.
|
|
5
|
+
*
|
|
6
|
+
* `snapshot.getMeta()` returns a FLAT record of the meta object of every active
|
|
7
|
+
* state. For a machine that is not parallel, that record is one chain of ancestors
|
|
8
|
+
* already. For a PARALLEL machine, it mixes the entries of every active region. A
|
|
9
|
+
* blind fold therefore joins a relative route of one region to an absolute route of
|
|
10
|
+
* a sibling region, and the URL belongs to the tree of neither region. The flat
|
|
11
|
+
* record also cannot go back into a hierarchy: when a state declares an explicit
|
|
12
|
+
* `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
|
|
13
|
+
* the meta keys are those ids, and they carry no information about the ancestry.
|
|
14
|
+
*
|
|
15
|
+
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
16
|
+
* the active states by the state key, against the node tree of the machine. It
|
|
17
|
+
* follows the FIRST active child at each level. This gives one deterministic branch,
|
|
18
|
+
* which matches the historical behavior of "the first that it finds" for a parallel
|
|
19
|
+
* machine. It also works with an explicit id, because each node carries its own `id`
|
|
20
|
+
* and its own `meta`.
|
|
21
|
+
*
|
|
22
|
+
* The function returns `null` when the snapshot exposes no machine and no value to
|
|
23
|
+
* walk. This is a defensive measure, because a real XState snapshot always exposes
|
|
24
|
+
* them. The caller then uses `getMeta()`, as before.
|
|
25
|
+
*/
|
|
26
|
+
export const firstActiveBranchMeta = (snapshot) => {
|
|
27
|
+
const root = snapshot.machine?.root;
|
|
28
|
+
if (!root)
|
|
29
|
+
return null;
|
|
30
|
+
const ordered = {};
|
|
31
|
+
let node = root;
|
|
32
|
+
let value = snapshot.value;
|
|
33
|
+
while (node) {
|
|
34
|
+
if (node.meta && typeof node.meta === "object") {
|
|
35
|
+
ordered[node.id] = node.meta; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
36
|
+
}
|
|
37
|
+
// Find the key of the active child at this level. A string value is the name of an
|
|
38
|
+
// atomic active leaf. An object value is a compound node, with one key, or a
|
|
39
|
+
// parallel node, with many keys: take the first key, for one deterministic
|
|
40
|
+
// branch.
|
|
41
|
+
let key;
|
|
42
|
+
if (typeof value === "string") {
|
|
43
|
+
key = value;
|
|
44
|
+
}
|
|
45
|
+
else if (value && typeof value === "object") {
|
|
46
|
+
key = Object.keys(value)[0];
|
|
47
|
+
}
|
|
48
|
+
if (key === undefined)
|
|
49
|
+
break;
|
|
50
|
+
const child = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
51
|
+
if (!child)
|
|
52
|
+
break;
|
|
53
|
+
value =
|
|
54
|
+
typeof value === "object" && value !== null
|
|
55
|
+
? value[key] // nosemgrep: gitlab.eslint.detect-object-injection
|
|
56
|
+
: {};
|
|
57
|
+
node = child;
|
|
58
|
+
}
|
|
59
|
+
return ordered;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Resolves the meta record that the route derivation and the view derivation fold:
|
|
63
|
+
* the single active branch that {@link firstActiveBranchMeta} walks, which is
|
|
64
|
+
* correct for a parallel machine and for an explicit id, or the flat `getMeta()`
|
|
65
|
+
* record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
|
|
66
|
+
* `deriveCurrentView` share this function. Therefore the two sides cannot move apart
|
|
67
|
+
* on the selection of the branch, and they cannot move apart on their tolerance of a
|
|
68
|
+
* degenerate snapshot.
|
|
69
|
+
*/
|
|
70
|
+
export const activeStateMeta = (snapshot) => {
|
|
71
|
+
if (!snapshot || typeof snapshot.getMeta !== "function") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const meta = firstActiveBranchMeta(snapshot) ?? snapshot.getMeta();
|
|
75
|
+
return meta && typeof meta === "object" ? meta : null;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=state-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-meta.js","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,QAA4B,EACK,EAAE;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,IAEnB,CAAC;IACb,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,IAAI,IAAI,GAA4B,IAAI,CAAC;IACzC,IAAI,KAAK,GAAY,QAAQ,CAAC,KAAK,CAAC;IAEpC,OAAO,IAAI,EAAE,CAAC;QACb,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,mDAAmD;QAClF,CAAC;QAED,mFAAmF;QACnF,6EAA6E;QAC7E,2EAA2E;QAC3E,UAAU;QACV,IAAI,GAAuB,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,GAAG,GAAG,KAAK,CAAC;QACb,CAAC;aAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/C,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAA4B,CAAC,CAAC,mDAAmD;QAChH,IAAI,CAAC,KAAK;YAAE,MAAM;QAClB,KAAK;YACJ,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;gBAC1C,CAAC,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,mDAAmD;gBAC7F,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,GAAG,KAAK,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAA4B,EAAkC,EAAE;IAC/F,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnE,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpF,CAAC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import type { ActorOptions, AnyStateMachine, InputFrom, SnapshotFrom } from "xstate";
|
|
2
2
|
import type { PlayerActor as PlayerActorClass } from "./player-actor.js";
|
|
3
|
+
import type { PlayerConstructor } from "./capabilities.js";
|
|
3
4
|
/**
|
|
4
5
|
* The configuration of definePlayer()
|
|
5
6
|
*/
|
|
6
|
-
export interface PlayerConfig<TMachine extends AnyStateMachine> {
|
|
7
|
+
export interface PlayerConfig<TMachine extends AnyStateMachine, TCapabilities extends object = object> {
|
|
7
8
|
/** The XState v5 state machine */
|
|
8
9
|
machine: TMachine;
|
|
9
10
|
/** The lifecycle hooks and the configuration */
|
|
10
11
|
options?: PlayerOptions<TMachine>;
|
|
12
|
+
/**
|
|
13
|
+
* The actor class to build, which decides which CAPABILITIES the actor carries.
|
|
14
|
+
*
|
|
15
|
+
* `PlayerActor` is the default, and it holds `state` and `send` alone. Compose a class
|
|
16
|
+
* to add a capability, and the factory then answers an actor with it:
|
|
17
|
+
*
|
|
18
|
+
* ```typescript
|
|
19
|
+
* definePlayer({ machine, actor: compose(PlayerActor, withRouting, withView) });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* An application that declares no route, and renders no view, passes nothing and loads
|
|
23
|
+
* neither body of code.
|
|
24
|
+
*/
|
|
25
|
+
actor?: PlayerConstructor<TMachine, TCapabilities>;
|
|
11
26
|
}
|
|
12
27
|
/**
|
|
13
28
|
* The lifecycle hooks of the player — the observability surface around the actor.
|
|
@@ -21,7 +36,7 @@ export interface PlayerOptions<TMachine extends AnyStateMachine> {
|
|
|
21
36
|
onStart?: (actor: PlayerActorClass<TMachine>) => void;
|
|
22
37
|
/**
|
|
23
38
|
* The actor calls it on each real stop, which means only after it tore a running
|
|
24
|
-
* actor down. A second `stop()` call,
|
|
39
|
+
* actor down. A second `stop()` call, and a stop of an
|
|
25
40
|
* actor that never started fire the hook not.
|
|
26
41
|
*/
|
|
27
42
|
onStop?: (actor: PlayerActorClass<TMachine>) => void;
|
|
@@ -32,7 +47,7 @@ export interface PlayerOptions<TMachine extends AnyStateMachine> {
|
|
|
32
47
|
* you.
|
|
33
48
|
*/
|
|
34
49
|
onTransition?: (actor: PlayerActorClass<TMachine>, prevState: SnapshotFrom<TMachine>, nextState: SnapshotFrom<TMachine>) => void;
|
|
35
|
-
/** The actor calls it when the state
|
|
50
|
+
/** The actor calls it when the state atom changes */
|
|
36
51
|
onStateChange?: (actor: PlayerActorClass<TMachine>, state: SnapshotFrom<TMachine>) => void;
|
|
37
52
|
/**
|
|
38
53
|
* The actor calls it on an actor error: a snapshot restore that fails at `start()`,
|
|
@@ -77,7 +92,7 @@ export interface PlayerOptions<TMachine extends AnyStateMachine> {
|
|
|
77
92
|
* inside the constructor of the actor. Its `actorRef` value is therefore the
|
|
78
93
|
* instance during the construction, and `state`, `currentRoute`, `currentView`, and
|
|
79
94
|
* `initialRoute` do not exist yet. A read of one of them there throws. Keep the
|
|
80
|
-
* reference, and read the
|
|
95
|
+
* reference, and read the atoms from a later event, or outside the observer.
|
|
81
96
|
*
|
|
82
97
|
* @example
|
|
83
98
|
* ```typescript
|
|
@@ -118,5 +133,5 @@ export interface PlayerFactoryResumeOptions<TMachine extends AnyStateMachine> {
|
|
|
118
133
|
* An absent input is then a compile error, and not an actor that starts in an error
|
|
119
134
|
* status with a `null` initial route.
|
|
120
135
|
*/
|
|
121
|
-
export type PlayerFactory<TMachine extends AnyStateMachine> = undefined extends InputFrom<TMachine> ? (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> : (input: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine
|
|
136
|
+
export type PlayerFactory<TMachine extends AnyStateMachine, TCapabilities extends object = object> = undefined extends InputFrom<TMachine> ? (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> & TCapabilities : (input: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> & TCapabilities;
|
|
122
137
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,YAAY,CAC5B,QAAQ,SAAS,eAAe,EAChC,aAAa,SAAS,MAAM,GAAG,MAAM;IAErC,kCAAkC;IAClC,OAAO,EAAE,QAAQ,CAAC;IAElB,gDAAgD;IAChD,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAElC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,eAAe;IAC9D;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEtD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAErD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CACd,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,KAC7B,IAAI,CAAC;IAEV,qDAAqD;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAE3F;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B,CAAC,QAAQ,SAAS,eAAe;IAC3E;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,QAAQ,SAAS,eAAe,EAAE,aAAa,SAAS,MAAM,GAAG,MAAM,IAChG,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC,GAClC,CACA,KAAK,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC3B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAAG,aAAa,GAC9C,CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC"}
|
|
@@ -2,22 +2,23 @@
|
|
|
2
2
|
* The view derivation — the meta.view half of the player pipeline.
|
|
3
3
|
*
|
|
4
4
|
* This file is beside src/routing/, so that player-actor.ts holds the actor
|
|
5
|
-
* itself only: the
|
|
5
|
+
* itself only: the atoms, the hooks, and the lifecycle. The walk over the active
|
|
6
6
|
* branch is shared with the route derivation. Therefore the view of a parallel
|
|
7
7
|
* machine always belongs to the region of its URL.
|
|
8
8
|
*/
|
|
9
9
|
import type { AnyMachineSnapshot } from "xstate";
|
|
10
|
-
import { type PlaySpec } from "@xmachines/play-
|
|
10
|
+
import { type PlaySpec } from "@xmachines/play-view";
|
|
11
11
|
/**
|
|
12
12
|
* Derives the current view of the actor from the state metadata.
|
|
13
13
|
*
|
|
14
14
|
* The function always returns a **fresh** `PlaySpec` object. The `Object.is`
|
|
15
|
-
* equality test of
|
|
16
|
-
* `
|
|
15
|
+
* equality test of the atom therefore stops no real change of the view.
|
|
16
|
+
* The `currentView` atom of `withView` decides if the actor emits that fresh object:
|
|
17
17
|
* it compares the object with the last spec of an emission, it reuses the reference
|
|
18
18
|
* of the composed `state` field when the value of the projection did not change, and
|
|
19
|
-
* it
|
|
20
|
-
*
|
|
19
|
+
* it returns the previous spec when the view on the screen is the same — which the
|
|
20
|
+
* `Object.is` compare of the atom reads as no change, so it notifies no subscriber. A
|
|
21
|
+
* provider below the actor therefore mounts the UI again not on every event.
|
|
21
22
|
*
|
|
22
23
|
* ### The context projection
|
|
23
24
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAyEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,kBAAkB,KAAG,QAAQ,GAAG,IA4C3E,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { composePlayState, toAtomState } from "@xmachines/play-
|
|
2
|
-
import { activeStateMeta } from "../
|
|
1
|
+
import { composePlayState, toAtomState } from "@xmachines/play-view";
|
|
2
|
+
import { activeStateMeta } from "../state-meta.js";
|
|
3
3
|
/**
|
|
4
4
|
* The migration warning of the `contextProps` field, which 1.x removed. The code
|
|
5
5
|
* writes it one time for each spec. A meta.view object from a person passes around
|
|
@@ -59,12 +59,13 @@ const resolveViewMeta = (meta) => {
|
|
|
59
59
|
* Derives the current view of the actor from the state metadata.
|
|
60
60
|
*
|
|
61
61
|
* The function always returns a **fresh** `PlaySpec` object. The `Object.is`
|
|
62
|
-
* equality test of
|
|
63
|
-
* `
|
|
62
|
+
* equality test of the atom therefore stops no real change of the view.
|
|
63
|
+
* The `currentView` atom of `withView` decides if the actor emits that fresh object:
|
|
64
64
|
* it compares the object with the last spec of an emission, it reuses the reference
|
|
65
65
|
* of the composed `state` field when the value of the projection did not change, and
|
|
66
|
-
* it
|
|
67
|
-
*
|
|
66
|
+
* it returns the previous spec when the view on the screen is the same — which the
|
|
67
|
+
* `Object.is` compare of the atom reads as no change, so it notifies no subscriber. A
|
|
68
|
+
* provider below the actor therefore mounts the UI again not on every event.
|
|
68
69
|
*
|
|
69
70
|
* ### The context projection
|
|
70
71
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAiB,MAAM,
|
|
1
|
+
{"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The routing capability of an XState actor, as a mixin.
|
|
3
|
+
*
|
|
4
|
+
* `PlayerActor` holds `state` and `send`, and nothing about a route. This module adds
|
|
5
|
+
* `currentRoute` and `initialRoute`, which is what `Routable` of `@xmachines/play-router`
|
|
6
|
+
* asks for and what every router bridge reads.
|
|
7
|
+
*
|
|
8
|
+
* It is a SEPARATE entry point, `@xmachines/play-xstate/routing`, and the core imports it
|
|
9
|
+
* never. `@xmachines/play-router` is an OPTIONAL peer of this package for the same reason:
|
|
10
|
+
* an application that declares no route installs neither that package nor the route map
|
|
11
|
+
* and the bridge that it carries.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
|
|
16
|
+
* import { withRouting } from "@xmachines/play-xstate/routing";
|
|
17
|
+
*
|
|
18
|
+
* const createPlayer = definePlayer({ machine, actor: compose(PlayerActor, withRouting) });
|
|
19
|
+
* const actor = createPlayer();
|
|
20
|
+
* actor.currentRoute.get(); // "/profile/alice"
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
import type { AnyStateMachine } from "xstate";
|
|
26
|
+
import type { Routable } from "@xmachines/play-router";
|
|
27
|
+
import type { PlayerConstructor } from "./capabilities.js";
|
|
28
|
+
/**
|
|
29
|
+
* Adds the routing capability to an actor class.
|
|
30
|
+
*
|
|
31
|
+
* The result satisfies `Routable`, so a router bridge accepts it. A class without this
|
|
32
|
+
* mixin exposes no `currentRoute`, and a bridge therefore refuses it when it compiles,
|
|
33
|
+
* rather than at the first navigation.
|
|
34
|
+
*
|
|
35
|
+
* The mixin declares NO constructor, and that is deliberate: TypeScript demands the
|
|
36
|
+
* signature `...args: any[]` from a mixin over a generic base (TS2545), and this
|
|
37
|
+
* workspace writes no `any`. A field initializer of a subclass runs after `super()`
|
|
38
|
+
* instead, and it reads the inputs that `PlayerActor` keeps for a capability.
|
|
39
|
+
*
|
|
40
|
+
* @param Base - The actor class to extend, normally `PlayerActor`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function withRouting<TMachine extends AnyStateMachine>(Base: PlayerConstructor<TMachine>): PlayerConstructor<TMachine, Routable>;
|
|
43
|
+
export { deriveRoute, isAbsoluteRoute, buildRouteUrl, formatPlayRouteTransitions, } from "./routing/index.js";
|
|
44
|
+
export type { RouteMachineConfig, RouteStateNode, RouteContext, RouteObject, RouteMetadata, RouteData, RouteDataResolver, } from "./routing/index.js";
|
|
45
|
+
//# sourceMappingURL=with-routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-routing.d.ts","sourceRoot":"","sources":["../src/with-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,QAAQ,SAAS,eAAe,EAC3D,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAC/B,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAiHvC;AAcD,OAAO,EACN,WAAW,EACX,eAAe,EACf,aAAa,EACb,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACX,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,GACjB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createAtom } from "@xmachines/play-atom";
|
|
2
|
+
import { deriveCurrentRoute, deriveInitialRoute } from "./routing/index.js";
|
|
3
|
+
import { toError } from "./player-actor.js";
|
|
4
|
+
/**
|
|
5
|
+
* Adds the routing capability to an actor class.
|
|
6
|
+
*
|
|
7
|
+
* The result satisfies `Routable`, so a router bridge accepts it. A class without this
|
|
8
|
+
* mixin exposes no `currentRoute`, and a bridge therefore refuses it when it compiles,
|
|
9
|
+
* rather than at the first navigation.
|
|
10
|
+
*
|
|
11
|
+
* The mixin declares NO constructor, and that is deliberate: TypeScript demands the
|
|
12
|
+
* signature `...args: any[]` from a mixin over a generic base (TS2545), and this
|
|
13
|
+
* workspace writes no `any`. A field initializer of a subclass runs after `super()`
|
|
14
|
+
* instead, and it reads the inputs that `PlayerActor` keeps for a capability.
|
|
15
|
+
*
|
|
16
|
+
* @param Base - The actor class to extend, normally `PlayerActor`.
|
|
17
|
+
*/
|
|
18
|
+
export function withRouting(Base) {
|
|
19
|
+
class RoutableActor extends Base {
|
|
20
|
+
/**
|
|
21
|
+
* A computed atom. It derives the current URL path from the `meta.route`
|
|
22
|
+
* template of the active machine state and from the context of the actor.
|
|
23
|
+
*
|
|
24
|
+
* It returns `null` when the current state has no `meta.route` field, and also when
|
|
25
|
+
* a necessary `:param` has no value in the context. The second case is normally
|
|
26
|
+
* temporary during a transition, and the atom computes the value again on the next
|
|
27
|
+
* snapshot.
|
|
28
|
+
*
|
|
29
|
+
* It THROWS never. A derivation of this architecture reports a failure through
|
|
30
|
+
* `onError` and keeps its last good value, and `currentView` of
|
|
31
|
+
* `@xmachines/play-xstate/view` follows the same rule.
|
|
32
|
+
*
|
|
33
|
+
* The reason is the propagation. A subscriber makes this atom eager, so the
|
|
34
|
+
* derivation runs inside the `set` of `state`, which runs inside the XState
|
|
35
|
+
* subscription. A throw that left this function would unwind into `actor.send` and
|
|
36
|
+
* break the transition for EVERY other observer of the actor.
|
|
37
|
+
*
|
|
38
|
+
* The containment therefore belongs to the derivation, and not to each subscriber:
|
|
39
|
+
* a consumer that writes its own `watchAtom(actor.currentRoute, ...)` is protected
|
|
40
|
+
* by the same rule that protects a router bridge.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // It returns "/profile/alice" when context.params.userId === "alice",
|
|
45
|
+
* // and null while the param is still absent.
|
|
46
|
+
* const route = actor.currentRoute.get();
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
currentRoute = createAtom((previous) => {
|
|
50
|
+
try {
|
|
51
|
+
return deriveCurrentRoute(this.state.get());
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// `deriveCurrentRoute` answers the EXPECTED failure itself: a missing `:param`
|
|
55
|
+
// returns `null`, and the next snapshot resolves it. Whatever reaches this line
|
|
56
|
+
// is unexpected — a `URIError` of `encodeURIComponent` for a lone surrogate,
|
|
57
|
+
// for example. Report it, and keep the last route: a caller that reads `null`
|
|
58
|
+
// or a stale route navigates nowhere, which the bridge handles already.
|
|
59
|
+
// The derivation runs inside the `set` of `state`, and the engine TRACKS every
|
|
60
|
+
// atom that this function reads — the handler of the host included. A report
|
|
61
|
+
// from HERE therefore made whatever that handler reads a dependency of this
|
|
62
|
+
// atom, and an unrelated write of it re-derived and reported again: three
|
|
63
|
+
// reports for one failure. The microtask leaves the evaluation, so the handler
|
|
64
|
+
// reads what it likes and this atom depends on none of it.
|
|
65
|
+
//
|
|
66
|
+
// It leaves the `set` as well, which is what the comment below already needed:
|
|
67
|
+
// a throw from the handler lands on the global handler of the runtime, and it
|
|
68
|
+
// breaks the transition for no other observer of the actor.
|
|
69
|
+
const onError = this.hooks.onError;
|
|
70
|
+
if (onError) {
|
|
71
|
+
const reported = toError(error);
|
|
72
|
+
queueMicrotask(() => {
|
|
73
|
+
onError(this, reported);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return previous ?? null;
|
|
77
|
+
}
|
|
78
|
+
}, {
|
|
79
|
+
// Every WRITE of `state` reaches an observer of this atom, and not the writes
|
|
80
|
+
// that change the route alone.
|
|
81
|
+
//
|
|
82
|
+
// The default `Object.is` stops a notification for a value that the atom holds
|
|
83
|
+
// already, and a route is a STRING: a guard that refuses an inbound location and
|
|
84
|
+
// moves the actor back to the state it came from derives the same string, so no
|
|
85
|
+
// observer heard the answer. `RouterBridgeBase` waits for exactly that answer —
|
|
86
|
+
// `syncActorFromRouter` clears `lastActorRoute` before it sends, so the push
|
|
87
|
+
// that puts the address bar back on the route of the machine is owed to this
|
|
88
|
+
// notification — and the address bar kept the location that the guard refused.
|
|
89
|
+
//
|
|
90
|
+
// The bridge is written against a notification for each change of the SNAPSHOT,
|
|
91
|
+
// and not for each change of the derived string, so the comparison has to answer
|
|
92
|
+
// "different" always. A consumer that reads the value pays nothing for it: the
|
|
93
|
+
// derivation still runs one time for each transition, and `state` itself compares
|
|
94
|
+
// with `Object.is`, so an event that XState ignores delivers the identical
|
|
95
|
+
// snapshot and propagates nothing.
|
|
96
|
+
compare: () => false,
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* The route of the initial state of the machine. The construction fixes it, and it
|
|
100
|
+
* never changes, also when the code restores the actor from a snapshot.
|
|
101
|
+
*
|
|
102
|
+
* A router bridge compares it with the browser URL, and it therefore separates a
|
|
103
|
+
* deep link (a URL that is not the initial one → the router wins) from a restore
|
|
104
|
+
* (the initial URL, and the actor at a different route from the restore → the actor
|
|
105
|
+
* wins).
|
|
106
|
+
*
|
|
107
|
+
* `deriveInitialRoute` derives the value statically from the machine definition,
|
|
108
|
+
* with the pure `initialTransition` helper of XState: the chain of the initial states
|
|
109
|
+
* and their `meta.route` templates are fixed at the moment of the machine
|
|
110
|
+
* definition, and the substitution of a `:param` uses the real initial context of
|
|
111
|
+
* the machine for the `input` of this actor. The code makes no second actor, and a
|
|
112
|
+
* snapshot of a restore changes the value never: it is always the **default**
|
|
113
|
+
* initial route of the machine.
|
|
114
|
+
*
|
|
115
|
+
* Without a snapshot of a restore, the pre-start snapshot of this actor IS that
|
|
116
|
+
* default initial state, so the code derives the route from it directly. A restore
|
|
117
|
+
* alone needs `initialTransition`, whose inert actor scope runs the initial
|
|
118
|
+
* transition two more times, one of them with an undefined `input`. That is a quirk
|
|
119
|
+
* of XState, and it costs too much for every other case.
|
|
120
|
+
*/
|
|
121
|
+
initialRoute = this.playerRestoredSnapshot === undefined
|
|
122
|
+
? deriveCurrentRoute(this.getSnapshot())
|
|
123
|
+
: deriveInitialRoute(this.playerMachine, this.playerInput);
|
|
124
|
+
}
|
|
125
|
+
return RoutableActor;
|
|
126
|
+
}
|
|
127
|
+
// The utilities of the route derivation and of the URL construction.
|
|
128
|
+
//
|
|
129
|
+
// They belong HERE, and no longer on the main entry. Each one names
|
|
130
|
+
// `@xmachines/play-router` in its own `.d.ts` — `PlayRouteEvent`, `RouteData`,
|
|
131
|
+
// `RouteObject` and `RouteMetadata` all have their single definition there. That
|
|
132
|
+
// package is an OPTIONAL peer, so a main entry that reached them gave every consumer
|
|
133
|
+
// of `definePlayer` a type graph that names a package their node_modules does not
|
|
134
|
+
// hold. `skipLibCheck` hides the fault and does not remove it: the types resolve to
|
|
135
|
+
// nothing.
|
|
136
|
+
//
|
|
137
|
+
// The view half exposes nothing on the main entry, for the same reason. The two
|
|
138
|
+
// capabilities hold one shape.
|
|
139
|
+
export { deriveRoute, isAbsoluteRoute, buildRouteUrl, formatPlayRouteTransitions, } from "./routing/index.js";
|
|
140
|
+
//# sourceMappingURL=with-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-routing.js","sourceRoot":"","sources":["../src/with-routing.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKlD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAC1B,IAAiC;IAEjC,MAAM,aAAc,SAAQ,IAAI;QAC/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BG;QACa,YAAY,GAAgC,UAAU,CACrE,CAAC,QAAQ,EAAiB,EAAE;YAC3B,IAAI,CAAC;gBACJ,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,+EAA+E;gBAC/E,gFAAgF;gBAChF,6EAA6E;gBAC7E,8EAA8E;gBAC9E,wEAAwE;gBACxE,+EAA+E;gBAC/E,6EAA6E;gBAC7E,4EAA4E;gBAC5E,0EAA0E;gBAC1E,+EAA+E;gBAC/E,2DAA2D;gBAC3D,EAAE;gBACF,+EAA+E;gBAC/E,8EAA8E;gBAC9E,4DAA4D;gBAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;gBACnC,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;oBAChC,cAAc,CAAC,GAAG,EAAE;wBACnB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;oBACzB,CAAC,CAAC,CAAC;gBACJ,CAAC;gBACD,OAAO,QAAQ,IAAI,IAAI,CAAC;YACzB,CAAC;QACF,CAAC,EACD;YACC,8EAA8E;YAC9E,+BAA+B;YAC/B,EAAE;YACF,+EAA+E;YAC/E,iFAAiF;YACjF,gFAAgF;YAChF,gFAAgF;YAChF,6EAA6E;YAC7E,6EAA6E;YAC7E,+EAA+E;YAC/E,EAAE;YACF,gFAAgF;YAChF,iFAAiF;YACjF,+EAA+E;YAC/E,kFAAkF;YAClF,2EAA2E;YAC3E,mCAAmC;YACnC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;SACpB,CACD,CAAC;QAEF;;;;;;;;;;;;;;;;;;;;;;WAsBG;QACa,YAAY,GAC3B,IAAI,CAAC,sBAAsB,KAAK,SAAS;YACxC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;KAC7D;IAED,OAAO,aAAa,CAAC;AACtB,CAAC;AAED,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,+EAA+E;AAC/E,iFAAiF;AACjF,qFAAqF;AACrF,kFAAkF;AAClF,oFAAoF;AACpF,WAAW;AACX,EAAE;AACF,gFAAgF;AAChF,+BAA+B;AAC/B,OAAO,EACN,WAAW,EACX,eAAe,EACf,aAAa,EACb,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The view capability of an XState actor, as a mixin.
|
|
3
|
+
*
|
|
4
|
+
* `PlayerActor` holds `state` and `send`, and nothing about a view. This module adds
|
|
5
|
+
* `currentView`, which is what `Viewable` of `@xmachines/play-view` asks for and what
|
|
6
|
+
* every renderer reads.
|
|
7
|
+
*
|
|
8
|
+
* It is a SEPARATE entry point, `@xmachines/play-xstate/view`, and the core imports it
|
|
9
|
+
* never. `@xmachines/play-view` is an OPTIONAL peer of this package for the same reason:
|
|
10
|
+
* an application that renders no view installs neither that package nor the json-render
|
|
11
|
+
* types that it names.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
|
|
16
|
+
* import { withRouting } from "@xmachines/play-xstate/routing";
|
|
17
|
+
* import { withView } from "@xmachines/play-xstate/view";
|
|
18
|
+
*
|
|
19
|
+
* const createPlayer = definePlayer({
|
|
20
|
+
* machine,
|
|
21
|
+
* actor: compose(PlayerActor, withRouting, withView),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @packageDocumentation
|
|
26
|
+
*/
|
|
27
|
+
import type { AnyStateMachine } from "xstate";
|
|
28
|
+
import { type Viewable } from "@xmachines/play-view";
|
|
29
|
+
import type { PlayerConstructor } from "./capabilities.js";
|
|
30
|
+
/**
|
|
31
|
+
* Two WeakMaps stood here, and the derivation below needs neither.
|
|
32
|
+
*
|
|
33
|
+
* `lastViewSnapshots` skipped the derivation for a snapshot that the pipeline read
|
|
34
|
+
* already, because XState notifies each observer on EVERY event that it processes and an
|
|
35
|
+
* event that it ignores delivers the identical snapshot again. A computed atom answers
|
|
36
|
+
* that by itself: `state.set(snapshot)` compares with `Object.is`, an identical reference
|
|
37
|
+
* therefore propagates nothing, and this atom stays valid.
|
|
38
|
+
*
|
|
39
|
+
* `lastEmittedViews` held the previous emission for the equality gate, because a read of
|
|
40
|
+
* `currentView` would have registered it as a dependency of the computation around the
|
|
41
|
+
* call and `@xstate/store` exports no `untrack`. The `previous` parameter of a computed
|
|
42
|
+
* atom is that same value, and the engine hands it in rather than tracking a read.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Adds the view capability to an actor class.
|
|
46
|
+
*
|
|
47
|
+
* The ORDER of the composition does not matter. `currentView` and `currentRoute` are two
|
|
48
|
+
* computed atoms over `state`, and neither reads the other, so the engine evaluates both
|
|
49
|
+
* from one write in topological order. An earlier release wrote `currentView` from an
|
|
50
|
+
* `onSnapshot` override, and the order then decided which capability held its new value
|
|
51
|
+
* first.
|
|
52
|
+
*
|
|
53
|
+
* @param Base - The actor class to extend, normally `PlayerActor` or the result of
|
|
54
|
+
* another capability.
|
|
55
|
+
*/
|
|
56
|
+
export declare function withView<TMachine extends AnyStateMachine>(Base: PlayerConstructor<TMachine>): PlayerConstructor<TMachine, Viewable>;
|
|
57
|
+
//# sourceMappingURL=with-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-view.d.ts","sourceRoot":"","sources":["../src/with-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAI9C,OAAO,EAAqC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAsC3D;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAS,eAAe,EACxD,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAC/B,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAuFvC"}
|