@koordinates/xstate-tree 5.1.0-next.1 → 5.1.0-next.11
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 +36 -0
- package/lib/builders.js +11 -1
- package/lib/routing/handleLocationChange/handleLocationChange.js +2 -2
- package/lib/routing/matchRoute/matchRoute.js +1 -1
- package/lib/utils.js +1 -10
- package/lib/xstate-tree.d.ts +45 -17
- package/lib/xstateTree.js +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,6 +185,42 @@ These events can be added anywhere, either next to a component for component spe
|
|
|
185
185
|
2. If they are tied to a component they need to be in the index.ts file that imports the view/selectors/actions etc and calls `createXStateTreeMachine`. If they are in the file containing those functions the index.d.ts file will not end up importing them.
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
### Utilities
|
|
189
|
+
|
|
190
|
+
#### `viewToMachine`
|
|
191
|
+
|
|
192
|
+
This utility accepts a React view that does not take any props and wraps it with an xstate-tree machine so you can easily invoke arbitrary React views in your xstate machines
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
function MyView() {
|
|
196
|
+
return <div>My View</div>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const MyViewMachine = viewToMachine(MyView);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### `buildRoutingMachine`
|
|
203
|
+
|
|
204
|
+
This utility aims to reduce boilerplate by generating a common type of state machine, a routing machine. This is a machine that solely consists of routing events that transition to states that invoke xstate-tree machines.
|
|
205
|
+
|
|
206
|
+
The first argument is the array of routes you wish to handle, and the second is an object mapping from those event types to the xstate-tree machine that will be invoked for that routing event
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
const routeA = createRoute.simpleRoute()({
|
|
210
|
+
url: "/a",
|
|
211
|
+
event: "GO_TO_A",
|
|
212
|
+
});
|
|
213
|
+
const routeB = createRoute.simpleRoute()({
|
|
214
|
+
url: "/b",
|
|
215
|
+
event: "GO_TO_B",
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const RoutingMachine = buildRoutingMachine([routeA, routeB], {
|
|
219
|
+
GO_TO_A: MachineA,
|
|
220
|
+
GO_TO_B: MachineB,
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
188
224
|
### Type helpers
|
|
189
225
|
|
|
190
226
|
There are some exported type helpers for use with xstate-tree
|
package/lib/builders.js
CHANGED
|
@@ -31,9 +31,19 @@ function createXStateTreeMachine(machine, options) {
|
|
|
31
31
|
View: options.View,
|
|
32
32
|
slots: (options.slots ?? []),
|
|
33
33
|
};
|
|
34
|
-
return machineWithMeta;
|
|
34
|
+
return fixProvideLosingXstateTreeMeta(machineWithMeta);
|
|
35
35
|
}
|
|
36
36
|
exports.createXStateTreeMachine = createXStateTreeMachine;
|
|
37
|
+
function fixProvideLosingXstateTreeMeta(machine) {
|
|
38
|
+
const originalProvide = machine.provide.bind(machine);
|
|
39
|
+
machine.provide = (impl) => {
|
|
40
|
+
const result = originalProvide(impl);
|
|
41
|
+
result._xstateTree = machine._xstateTree;
|
|
42
|
+
fixProvideLosingXstateTreeMeta(result);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
return machine;
|
|
46
|
+
}
|
|
37
47
|
/**
|
|
38
48
|
* @public
|
|
39
49
|
*
|
|
@@ -9,7 +9,6 @@ const matchRoute_1 = require("../matchRoute");
|
|
|
9
9
|
function handleLocationChange(routes, basePath, path, search, meta) {
|
|
10
10
|
console.debug("[xstate-tree] Matching routes", basePath, path, search, meta);
|
|
11
11
|
const match = (0, matchRoute_1.matchRoute)(routes, basePath, path, search);
|
|
12
|
-
console.debug("[xstate-tree] Match result", match);
|
|
13
12
|
if (match.type === "no-matches") {
|
|
14
13
|
const fourOhFour = {
|
|
15
14
|
type: "ROUTING_404",
|
|
@@ -20,10 +19,11 @@ function handleLocationChange(routes, basePath, path, search, meta) {
|
|
|
20
19
|
return;
|
|
21
20
|
}
|
|
22
21
|
else if (match.type === "match-error") {
|
|
23
|
-
console.error("Error matching route for", location.pathname);
|
|
22
|
+
console.error("Error matching route for", location.pathname, match.error);
|
|
24
23
|
return;
|
|
25
24
|
}
|
|
26
25
|
else {
|
|
26
|
+
console.log("[xstate-tree] matched route", match.event);
|
|
27
27
|
const matchedEvent = match.event;
|
|
28
28
|
matchedEvent.meta = { ...(meta ?? {}) };
|
|
29
29
|
matchedEvent.meta.indexEvent = true;
|
|
@@ -32,7 +32,7 @@ function matchRoute(routes, basePath, path, search) {
|
|
|
32
32
|
return { type: "no-matches" };
|
|
33
33
|
}
|
|
34
34
|
else if (matchingRoute instanceof Error) {
|
|
35
|
-
return { type: "match-error" };
|
|
35
|
+
return { type: "match-error", error: matchingRoute };
|
|
36
36
|
}
|
|
37
37
|
return { type: "matched", route: matchingRoute, event: event };
|
|
38
38
|
}
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toJSON = exports.mergeMeta = exports.isNil = exports.isEqual = exports.difference = exports.
|
|
3
|
+
exports.toJSON = exports.mergeMeta = exports.isNil = exports.isEqual = exports.difference = exports.assert = exports.assertIsDefined = exports.delay = void 0;
|
|
4
4
|
function delay(ms = 0) {
|
|
5
5
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
6
|
}
|
|
@@ -26,15 +26,6 @@ function assert(value, msg) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
exports.assert = assert;
|
|
29
|
-
function isLikelyPageLoad() {
|
|
30
|
-
// without performance API, we can't tell if this is a page load
|
|
31
|
-
if (typeof performance === "undefined") {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
// if it's been < 5 seconds since the page was loaded, it's probably a page load
|
|
35
|
-
return performance.now() < 5000;
|
|
36
|
-
}
|
|
37
|
-
exports.isLikelyPageLoad = isLikelyPageLoad;
|
|
38
29
|
function difference(a, b) {
|
|
39
30
|
const result = {};
|
|
40
31
|
for (const key in b) {
|
package/lib/xstate-tree.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export declare type AnyRoute = {
|
|
|
50
50
|
/**
|
|
51
51
|
* @public
|
|
52
52
|
*/
|
|
53
|
-
export declare type AnyXstateTreeMachine = XstateTreeMachine<AnyStateMachine>;
|
|
53
|
+
export declare type AnyXstateTreeMachine = XstateTreeMachine<AnyStateMachine, any, any, any[]>;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* @public
|
|
@@ -133,15 +133,11 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
133
133
|
* @param machine - The root machine of the tree
|
|
134
134
|
* @param routing - The routing configuration for the tree
|
|
135
135
|
*/
|
|
136
|
-
export declare function buildRootComponent(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
basePath: string;
|
|
140
|
-
getPathName?: () => string;
|
|
141
|
-
getQueryString?: () => string;
|
|
142
|
-
}): {
|
|
136
|
+
export declare function buildRootComponent<TMachine extends AnyXstateTreeMachine>(options: {
|
|
137
|
+
machine: TMachine;
|
|
138
|
+
} & MarkOptionalLikePropertiesOptional<RootOptions<InputFrom<TMachine>>>): {
|
|
143
139
|
(): JSX.Element;
|
|
144
|
-
rootMachine:
|
|
140
|
+
rootMachine: TMachine;
|
|
145
141
|
};
|
|
146
142
|
|
|
147
143
|
/**
|
|
@@ -177,7 +173,7 @@ export declare type CanHandleEvent<TMachine extends AnyStateMachine> = (e: Event
|
|
|
177
173
|
* @param machine - The xstate machine to create the xstate-tree machine from
|
|
178
174
|
* @param options - the xstate-tree options
|
|
179
175
|
*/
|
|
180
|
-
export declare function createXStateTreeMachine<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = []>(machine: TMachine, options: V2BuilderMeta<TMachine, TSelectorsOutput, TActionsOutput, TSlots>): XstateTreeMachine<TMachine>;
|
|
176
|
+
export declare function createXStateTreeMachine<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = []>(machine: TMachine, options: V2BuilderMeta<TMachine, TSelectorsOutput, TActionsOutput, TSlots>): XstateTreeMachine<TMachine, TSelectorsOutput, TActionsOutput, TSlots>;
|
|
181
177
|
|
|
182
178
|
declare type EmptyKeys<T> = keyof {
|
|
183
179
|
[K in keyof T as IsEmptyObject<T[K], true> extends true ? K : never]: T[K];
|
|
@@ -217,6 +213,8 @@ declare type IsEmptyObject<Obj, ExcludeOptional extends boolean = false> = undef
|
|
|
217
213
|
never
|
|
218
214
|
] ? true : false;
|
|
219
215
|
|
|
216
|
+
declare type IsUnknown<T> = unknown extends T ? true : false;
|
|
217
|
+
|
|
220
218
|
/**
|
|
221
219
|
* @public
|
|
222
220
|
*
|
|
@@ -278,7 +276,10 @@ export declare function loggingMetaOptions<TEvents extends EventObject, TContext
|
|
|
278
276
|
};
|
|
279
277
|
};
|
|
280
278
|
|
|
281
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Marks any required property that can accept undefined as optional
|
|
281
|
+
*/
|
|
282
|
+
declare type MarkOptionalLikePropertiesOptional<T> = Omit<T, EmptyKeys<T>> & Partial<Pick<T, EmptyKeys<T>>>;
|
|
282
283
|
|
|
283
284
|
/**
|
|
284
285
|
* @internal
|
|
@@ -328,7 +329,7 @@ declare type OmitOptional<T> = {
|
|
|
328
329
|
*/
|
|
329
330
|
export declare function onBroadcast(handler: (event: GlobalEvents) => void): () => void;
|
|
330
331
|
|
|
331
|
-
declare type Options<TStateMachine extends
|
|
332
|
+
declare type Options<TStateMachine extends AnyXstateTreeMachine> = {
|
|
332
333
|
/**
|
|
333
334
|
* Displayed while the promise is resolving, defaults to returning null
|
|
334
335
|
*/
|
|
@@ -369,6 +370,14 @@ export declare type Query<T> = T extends {
|
|
|
369
370
|
query: infer TQuery;
|
|
370
371
|
} ? TQuery : undefined;
|
|
371
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Repairs the return type of the `provide` function on XstateTreeMachines to correctly return
|
|
375
|
+
* an XstateTreeMachine type instead of an xstate StateMachine
|
|
376
|
+
*/
|
|
377
|
+
declare type RepairProvideReturnType<T extends AnyStateMachine, TSelectorsOutput, TActionsOutput, TSlots extends readonly Slot[]> = {
|
|
378
|
+
[K in keyof T]: K extends "provide" ? (...args: Parameters<T[K]>) => XstateTreeMachine<T, TSelectorsOutput, TActionsOutput, TSlots> : T[K];
|
|
379
|
+
};
|
|
380
|
+
|
|
372
381
|
declare type ResolveZodType<T extends Z.ZodType<any> | undefined> = undefined extends T ? undefined : Z.TypeOf<Exclude<T, undefined>>;
|
|
373
382
|
|
|
374
383
|
declare type Return<TRoutes extends Route<any, any, any, any>[]> = {
|
|
@@ -379,6 +388,18 @@ declare type Return<TRoutes extends Route<any, any, any, any>[]> = {
|
|
|
379
388
|
type: "no-matches";
|
|
380
389
|
} | {
|
|
381
390
|
type: "match-error";
|
|
391
|
+
error: unknown;
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
declare type RootOptions<TInput> = {
|
|
395
|
+
routing: {
|
|
396
|
+
routes: AnyRoute[];
|
|
397
|
+
history: XstateTreeHistory<any>;
|
|
398
|
+
basePath: string;
|
|
399
|
+
getPathName?: () => string;
|
|
400
|
+
getQueryString?: () => string;
|
|
401
|
+
} | undefined;
|
|
402
|
+
input: IsUnknown<TInput> extends true ? undefined : TInput;
|
|
382
403
|
};
|
|
383
404
|
|
|
384
405
|
/**
|
|
@@ -456,7 +477,7 @@ export declare type Route<TParams, TQuery, TEvent, TMeta> = {
|
|
|
456
477
|
/**
|
|
457
478
|
* @public
|
|
458
479
|
*/
|
|
459
|
-
export declare type RouteArgumentFunctions<TReturn, TParams, TQuery, TMeta, TArgs = RouteArguments<TParams, TQuery, TMeta>> = IsEmptyObject<TArgs> extends true ? () => TReturn : keyof TArgs extends "meta" ? (args?: TArgs) => TReturn : EmptyRouteArguments<TParams, TQuery> extends true ? (args?: Partial<TArgs>) => TReturn : (args:
|
|
480
|
+
export declare type RouteArgumentFunctions<TReturn, TParams, TQuery, TMeta, TArgs = RouteArguments<TParams, TQuery, TMeta>> = IsEmptyObject<TArgs> extends true ? () => TReturn : keyof TArgs extends "meta" ? (args?: TArgs) => TReturn : EmptyRouteArguments<TParams, TQuery> extends true ? (args?: Partial<TArgs>) => TReturn : (args: MarkOptionalLikePropertiesOptional<TArgs>) => TReturn;
|
|
460
481
|
|
|
461
482
|
/**
|
|
462
483
|
* @public
|
|
@@ -496,7 +517,14 @@ export declare type RouteMeta<T> = T extends Route<any, any, any, infer TMeta> ?
|
|
|
496
517
|
*/
|
|
497
518
|
export declare type RouteParams<T> = T extends Route<infer TParams, any, any, any> ? TParams : undefined;
|
|
498
519
|
|
|
499
|
-
|
|
520
|
+
/**
|
|
521
|
+
* @public
|
|
522
|
+
*
|
|
523
|
+
* Extract query type from route
|
|
524
|
+
*/
|
|
525
|
+
export declare type RouteQuery<T> = T extends Route<any, infer TQuery, any, any> ? TQuery : undefined;
|
|
526
|
+
|
|
527
|
+
declare type RouteRedirect<TParams, TQuery, TMeta> = (args: MarkOptionalLikePropertiesOptional<{
|
|
500
528
|
params: TParams;
|
|
501
529
|
query: TQuery;
|
|
502
530
|
meta?: TMeta;
|
|
@@ -696,13 +724,13 @@ export declare type XstateTreeHistory<T = unknown> = History_2<{
|
|
|
696
724
|
/**
|
|
697
725
|
* @public
|
|
698
726
|
*/
|
|
699
|
-
export declare type XstateTreeMachine<TMachine extends AnyStateMachine> = TMachine & XstateTreeMachineInjection<TMachine>;
|
|
727
|
+
export declare type XstateTreeMachine<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = Slot[]> = RepairProvideReturnType<TMachine, TSelectorsOutput, TActionsOutput, TSlots> & XstateTreeMachineInjection<TMachine, TSelectorsOutput, TActionsOutput, TSlots>;
|
|
700
728
|
|
|
701
729
|
/**
|
|
702
730
|
* @internal
|
|
703
731
|
*/
|
|
704
|
-
export declare type XstateTreeMachineInjection<TMachine extends AnyStateMachine> = {
|
|
705
|
-
_xstateTree: XstateTreeMachineStateSchemaV2<TMachine>;
|
|
732
|
+
export declare type XstateTreeMachineInjection<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = Slot[]> = {
|
|
733
|
+
_xstateTree: XstateTreeMachineStateSchemaV2<TMachine, TSelectorsOutput, TActionsOutput, TSlots>;
|
|
706
734
|
};
|
|
707
735
|
|
|
708
736
|
/**
|
package/lib/xstateTree.js
CHANGED
|
@@ -203,7 +203,8 @@ exports.recursivelySend = recursivelySend;
|
|
|
203
203
|
* @param machine - The root machine of the tree
|
|
204
204
|
* @param routing - The routing configuration for the tree
|
|
205
205
|
*/
|
|
206
|
-
function buildRootComponent(
|
|
206
|
+
function buildRootComponent(options) {
|
|
207
|
+
const { input, machine, routing } = options;
|
|
207
208
|
if (!machine._xstateTree) {
|
|
208
209
|
throw new Error("Root machine is not an xstate-tree machine, missing metadata");
|
|
209
210
|
}
|
|
@@ -213,6 +214,7 @@ function buildRootComponent(machine, routing) {
|
|
|
213
214
|
const RootComponent = function XstateTreeRootComponent() {
|
|
214
215
|
const lastSnapshotsRef = (0, react_2.useRef)({});
|
|
215
216
|
const [_, __, interpreter] = (0, react_1.useActor)(machine, {
|
|
217
|
+
input,
|
|
216
218
|
inspect(event) {
|
|
217
219
|
switch (event.type) {
|
|
218
220
|
case "@xstate.actor":
|
|
@@ -318,7 +320,7 @@ function buildRootComponent(machine, routing) {
|
|
|
318
320
|
const { getPathName = () => routing.history.location.pathname, getQueryString = () => routing.history.location.search, } = routing;
|
|
319
321
|
const initialMeta = {
|
|
320
322
|
...(routing.history.location.state?.meta ?? {}),
|
|
321
|
-
onloadEvent:
|
|
323
|
+
onloadEvent: true,
|
|
322
324
|
};
|
|
323
325
|
const queryString = getQueryString();
|
|
324
326
|
const result = (0, routing_1.handleLocationChange)(routing.routes, routing.basePath, getPathName(), getQueryString(), initialMeta);
|
package/package.json
CHANGED