@koordinates/xstate-tree 5.1.0-next.1 → 5.1.0-next.10

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 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
@@ -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.isLikelyPageLoad = exports.assert = exports.assertIsDefined = exports.delay = void 0;
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) {
@@ -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(machine: AnyXstateTreeMachine, routing?: {
137
- routes: AnyRoute[];
138
- history: XstateTreeHistory<any>;
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: AnyXstateTreeMachine;
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
- declare type MakeEmptyObjectPropertiesOptional<T> = Omit<T, EmptyKeys<T>> & Partial<Pick<T, EmptyKeys<T>>>;
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
@@ -379,6 +380,18 @@ declare type Return<TRoutes extends Route<any, any, any, any>[]> = {
379
380
  type: "no-matches";
380
381
  } | {
381
382
  type: "match-error";
383
+ error: unknown;
384
+ };
385
+
386
+ declare type RootOptions<TInput> = {
387
+ routing: {
388
+ routes: AnyRoute[];
389
+ history: XstateTreeHistory<any>;
390
+ basePath: string;
391
+ getPathName?: () => string;
392
+ getQueryString?: () => string;
393
+ } | undefined;
394
+ input: IsUnknown<TInput> extends true ? undefined : TInput;
382
395
  };
383
396
 
384
397
  /**
@@ -456,7 +469,7 @@ export declare type Route<TParams, TQuery, TEvent, TMeta> = {
456
469
  /**
457
470
  * @public
458
471
  */
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: MakeEmptyObjectPropertiesOptional<TArgs>) => TReturn;
472
+ 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
473
 
461
474
  /**
462
475
  * @public
@@ -496,7 +509,14 @@ export declare type RouteMeta<T> = T extends Route<any, any, any, infer TMeta> ?
496
509
  */
497
510
  export declare type RouteParams<T> = T extends Route<infer TParams, any, any, any> ? TParams : undefined;
498
511
 
499
- declare type RouteRedirect<TParams, TQuery, TMeta> = (args: MakeEmptyObjectPropertiesOptional<{
512
+ /**
513
+ * @public
514
+ *
515
+ * Extract query type from route
516
+ */
517
+ export declare type RouteQuery<T> = T extends Route<any, infer TQuery, any, any> ? TQuery : undefined;
518
+
519
+ declare type RouteRedirect<TParams, TQuery, TMeta> = (args: MarkOptionalLikePropertiesOptional<{
500
520
  params: TParams;
501
521
  query: TQuery;
502
522
  meta?: TMeta;
@@ -696,13 +716,13 @@ export declare type XstateTreeHistory<T = unknown> = History_2<{
696
716
  /**
697
717
  * @public
698
718
  */
699
- export declare type XstateTreeMachine<TMachine extends AnyStateMachine> = TMachine & XstateTreeMachineInjection<TMachine>;
719
+ export declare type XstateTreeMachine<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = Slot[]> = TMachine & XstateTreeMachineInjection<TMachine, TSelectorsOutput, TActionsOutput, TSlots>;
700
720
 
701
721
  /**
702
722
  * @internal
703
723
  */
704
- export declare type XstateTreeMachineInjection<TMachine extends AnyStateMachine> = {
705
- _xstateTree: XstateTreeMachineStateSchemaV2<TMachine>;
724
+ export declare type XstateTreeMachineInjection<TMachine extends AnyStateMachine, TSelectorsOutput = ContextFrom<TMachine>, TActionsOutput = Record<never, string>, TSlots extends readonly Slot[] = Slot[]> = {
725
+ _xstateTree: XstateTreeMachineStateSchemaV2<TMachine, TSelectorsOutput, TActionsOutput, TSlots>;
706
726
  };
707
727
 
708
728
  /**
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(machine, routing) {
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: (0, utils_1.isLikelyPageLoad)(),
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
@@ -2,7 +2,7 @@
2
2
  "name": "@koordinates/xstate-tree",
3
3
  "main": "lib/index.js",
4
4
  "types": "lib/xstate-tree.d.ts",
5
- "version": "5.1.0-next.1",
5
+ "version": "5.1.0-next.10",
6
6
  "license": "MIT",
7
7
  "description": "Build UIs with Actors using xstate and React",
8
8
  "keywords": [