@koordinates/xstate-tree 5.1.0-next.9 → 5.2.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 +123 -54
- package/lib/builders.js +21 -3
- package/lib/index.js +2 -1
- package/lib/routing/createRoute/createRoute.js +12 -1
- package/lib/routing/index.js +4 -1
- package/lib/routing/providers.js +13 -2
- package/lib/routing/useOnRoute.js +23 -0
- package/lib/utils.js +6 -3
- package/lib/xstate-tree.d.ts +38 -6
- package/lib/xstateTree.js +22 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,10 +20,9 @@ A minimal example of a single machine tree:
|
|
|
20
20
|
```tsx
|
|
21
21
|
import React from "react";
|
|
22
22
|
import { createRoot } from "react-dom/client";
|
|
23
|
-
import {
|
|
24
|
-
import { assign } from "@xstate/immer";
|
|
23
|
+
import { setup, assign, assertEvent } from "xstate";
|
|
25
24
|
import {
|
|
26
|
-
createXStateTreeMachine
|
|
25
|
+
createXStateTreeMachine,
|
|
27
26
|
buildRootComponent
|
|
28
27
|
} from "@koordinates/xstate-tree";
|
|
29
28
|
|
|
@@ -32,40 +31,37 @@ type Events =
|
|
|
32
31
|
| { type: "INCREMENT"; amount: number };
|
|
33
32
|
type Context = { incremented: number };
|
|
34
33
|
|
|
35
|
-
// A standard xstate machine, nothing extra is needed for xstate-tree
|
|
36
|
-
const machine =
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
states: {
|
|
44
|
-
inactive: {
|
|
45
|
-
on: {
|
|
46
|
-
SWITCH_CLICKED: "active"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
active: {
|
|
50
|
-
on: {
|
|
51
|
-
SWITCH_CLICKED: "inactive",
|
|
52
|
-
INCREMENT: { actions: "increment" }
|
|
53
|
-
}
|
|
34
|
+
// A standard xstate v5 machine, nothing extra is needed for xstate-tree
|
|
35
|
+
const machine = setup({
|
|
36
|
+
types: { context: {} as Context, events: {} as Events },
|
|
37
|
+
actions: {
|
|
38
|
+
increment: assign({
|
|
39
|
+
incremented: ({ context, event }) => {
|
|
40
|
+
assertEvent(event, "INCREMENT");
|
|
41
|
+
return context.incremented + event.amount;
|
|
54
42
|
}
|
|
55
|
-
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
}).createMachine({
|
|
46
|
+
id: "root",
|
|
47
|
+
initial: "inactive",
|
|
48
|
+
context: {
|
|
49
|
+
incremented: 0
|
|
56
50
|
},
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
states: {
|
|
52
|
+
inactive: {
|
|
53
|
+
on: {
|
|
54
|
+
SWITCH_CLICKED: "active"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
active: {
|
|
58
|
+
on: {
|
|
59
|
+
SWITCH_CLICKED: "inactive",
|
|
60
|
+
INCREMENT: { actions: "increment" }
|
|
61
|
+
}
|
|
66
62
|
}
|
|
67
63
|
}
|
|
68
|
-
);
|
|
64
|
+
});
|
|
69
65
|
|
|
70
66
|
const RootMachine = createXStateTreeMachine(machine, {
|
|
71
67
|
// Selectors to transform the machines state into a representation useful for the view
|
|
@@ -95,10 +91,10 @@ const RootMachine = createXStateTreeMachine(machine, {
|
|
|
95
91
|
// If this tree had more than a single machine the slots to render child machines into would be defined here
|
|
96
92
|
// see the codesandbox example for an expanded demonstration that uses slots
|
|
97
93
|
slots: [],
|
|
98
|
-
// A view to bring it all together
|
|
99
|
-
// the return value is a plain React
|
|
94
|
+
// A React component view to bring it all together
|
|
95
|
+
// the return value is a plain React component that can be rendered anywhere by passing in the needed props
|
|
100
96
|
// the view has no knowledge of the machine it's bound to
|
|
101
|
-
|
|
97
|
+
View({ actions, selectors }) {
|
|
102
98
|
return (
|
|
103
99
|
<div>
|
|
104
100
|
<button onClick={() => actions.switch()}>
|
|
@@ -118,6 +114,7 @@ const RootMachine = createXStateTreeMachine(machine, {
|
|
|
118
114
|
});
|
|
119
115
|
|
|
120
116
|
// Build the React host for the tree
|
|
117
|
+
// You can pass input to the machine via the input prop
|
|
121
118
|
const XstateTreeRoot = buildRootComponent(RootMachine);
|
|
122
119
|
|
|
123
120
|
// Rendering it with React
|
|
@@ -133,7 +130,7 @@ Each machine that forms the tree representing your UI has an associated set of s
|
|
|
133
130
|
- Selector functions are provided with the current context of the machine, a function to determine if it can handle a given event and a function to determine if it is in a given state, and expose the returned result to the view.
|
|
134
131
|
- Action functions are provided with the `send` method bound to the machines interpreter and the result of calling the selector function
|
|
135
132
|
- Slots are how children of the machine are exposed to the view. They can be either single slot for a single actor, or multi slot for when you have a list of actors.
|
|
136
|
-
- View functions are React
|
|
133
|
+
- View functions are React components provided with the output of the selector and action functions, and the currently active slots
|
|
137
134
|
|
|
138
135
|
## API
|
|
139
136
|
|
|
@@ -142,7 +139,7 @@ To assist in making xstate-tree easy to use with TypeScript there is the `create
|
|
|
142
139
|
`createXStateTreeMachine` accepts the xstate machine as the first argument and takes an options argument with the following fields, it is important the fields are defined in this order or TypeScript will infer the wrong types:
|
|
143
140
|
* `selectors`, receives an object with `ctx`, `inState`, `canHandleEvent`, and `meta` fields. `ctx` is the machines current context, `inState` is the xstate `state.matches` function to allow determining if the machine is in a given state, and `canHandleEvent` accepts an event object and returns whether the machine will do anything in response to that event in it's current state. `meta` is the xstate `state.meta` object with all the per state meta flattened into an object
|
|
144
141
|
* `actions`, receives an object with `send` and `selectors` fields. `send` is the xstate `send` function bound to the machine, and `selectors` is the result of calling the selector function
|
|
145
|
-
* `
|
|
142
|
+
* `View`, is a React component (note the capital V) that receives `actions`, `selectors`, and `slots` as props. `actions` and `selectors` being the result of the action/selector functions and `slots` being an object with keys as the slot names and the values the slots React component
|
|
146
143
|
|
|
147
144
|
Full API docs coming soon, see [#20](https://github.com/koordinates/xstate-tree/issues/20)
|
|
148
145
|
|
|
@@ -189,11 +186,11 @@ These events can be added anywhere, either next to a component for component spe
|
|
|
189
186
|
|
|
190
187
|
#### `viewToMachine`
|
|
191
188
|
|
|
192
|
-
This utility accepts a React
|
|
189
|
+
This utility accepts a React component and wraps it with an xstate-tree machine so you can easily invoke arbitrary React components in your xstate machines. This utility also accepts Root components returned from `buildRootComponent`.
|
|
193
190
|
|
|
194
|
-
```
|
|
191
|
+
```tsx
|
|
195
192
|
function MyView() {
|
|
196
|
-
return <div>My View</div>;
|
|
193
|
+
return <div>{"My View"}</div>;
|
|
197
194
|
}
|
|
198
195
|
|
|
199
196
|
const MyViewMachine = viewToMachine(MyView);
|
|
@@ -203,9 +200,9 @@ const MyViewMachine = viewToMachine(MyView);
|
|
|
203
200
|
|
|
204
201
|
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
202
|
|
|
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
|
|
203
|
+
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. The utility now supports routes with dots in their event names (e.g., "user.profile.view").
|
|
207
204
|
|
|
208
|
-
```
|
|
205
|
+
```tsx
|
|
209
206
|
const routeA = createRoute.simpleRoute()({
|
|
210
207
|
url: "/a",
|
|
211
208
|
event: "GO_TO_A",
|
|
@@ -227,25 +224,97 @@ There are some exported type helpers for use with xstate-tree
|
|
|
227
224
|
|
|
228
225
|
* `SelectorsFrom<TMachine>`: Takes a machine and returns the type of the selectors object
|
|
229
226
|
* `ActionsFrom<TMachine>`: Takes a machine and returns the type of the actions object
|
|
227
|
+
* `AnyXstateTreeMachine`: Type for any xstate-tree machine, useful for function parameters
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
### New Features in v5
|
|
231
|
+
|
|
232
|
+
#### `buildRootComponent` Input Support
|
|
233
|
+
|
|
234
|
+
You can now pass input to your root machine when using `buildRootComponent`. The function signature has changed to accept a single object parameter:
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
// Without routing
|
|
238
|
+
const XstateTreeRoot = buildRootComponent(RootMachine);
|
|
239
|
+
|
|
240
|
+
// With routing
|
|
241
|
+
const XstateTreeRoot = buildRootComponent({
|
|
242
|
+
machine: RootMachine,
|
|
243
|
+
routing: {
|
|
244
|
+
routes,
|
|
245
|
+
history,
|
|
246
|
+
basePath: "/"
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Pass input to the machine
|
|
251
|
+
ReactRoot.render(<XstateTreeRoot input={{ initialData: data }} />);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### `useOnRoute` Hook
|
|
230
255
|
|
|
256
|
+
A new hook for executing side effects when specific routes are active. Unlike `useIsRouteActive`, this hook tells you when you're on the exact route (not just part of the active route chain):
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
import { useOnRoute } from "@koordinates/xstate-tree";
|
|
260
|
+
|
|
261
|
+
function MyComponent() {
|
|
262
|
+
useOnRoute(myRoute, ({ params, query }) => {
|
|
263
|
+
// Execute side effects when myRoute is the active end route
|
|
264
|
+
console.log("Route is active with params:", params);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Children Support for Root Components
|
|
270
|
+
|
|
271
|
+
Root components and slots now support passing children, allowing you to wrap your application with providers:
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
<XstateTreeRoot>
|
|
275
|
+
<GlobalProvider>
|
|
276
|
+
{/* Your app renders here */}
|
|
277
|
+
</GlobalProvider>
|
|
278
|
+
</XstateTreeRoot>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Improved `lazy` Loading
|
|
282
|
+
|
|
283
|
+
The `lazy` utility now supports passing input to the lazily loaded machine:
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
const LazyMachine = lazy(() => import("./MyMachine"), {
|
|
287
|
+
Loader: () => <div>Loading...</div>,
|
|
288
|
+
input: { initialData: "data" }
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
#### Testing Improvements
|
|
293
|
+
|
|
294
|
+
- `TestRoutingContext` now supports nesting routing roots for better testing scenarios
|
|
295
|
+
- Removed deprecated testing utilities: `buildTestRootComponent`, `buildViewProps`, `slotTestingDummyFactory`
|
|
296
|
+
|
|
297
|
+
#### Logging Improvements
|
|
298
|
+
|
|
299
|
+
- Internal XState events are now filtered from logs for cleaner output
|
|
300
|
+
- `_subscription` property is stripped from logged data
|
|
301
|
+
- Route objects are no longer logged after matching to reduce console noise
|
|
302
|
+
- `loggingMetaOptions` export available for configuring logging behavior
|
|
303
|
+
|
|
304
|
+
### Breaking Changes from v4
|
|
305
|
+
|
|
306
|
+
- **Removed v1 style builders**: `buildView`, `buildSelectors`, `buildActions` have been removed. Use `createXStateTreeMachine` instead.
|
|
307
|
+
- **Child actor behavior**: Children in final states are no longer automatically removed from views. You must manually call `stopChild` to remove them.
|
|
308
|
+
- **Testing utilities removed**: `buildTestRootComponent`, `buildViewProps`, and `slotTestingDummyFactory` have been removed.
|
|
231
309
|
|
|
232
310
|
### [Storybook](https://storybook.js.org)
|
|
233
311
|
|
|
234
|
-
It is relatively simple to display xstate-tree views directly in Storybook. Since the views are plain React components that accept selectors/actions/slots
|
|
312
|
+
It is relatively simple to display xstate-tree views directly in Storybook. Since the views are plain React components that accept selectors/actions/slots as props you can just import the view and render it in a Story
|
|
235
313
|
|
|
236
|
-
There
|
|
314
|
+
There is a utility in xstate-tree to make this easier:
|
|
237
315
|
|
|
238
316
|
#### `genericSlotsTestingDummy`
|
|
239
317
|
|
|
240
318
|
This is a simple Proxy object that renders a <div> containing the name of the slot whenever rendering
|
|
241
319
|
a slot is attempted in the view. This will suffice as an argument for the slots prop in most views
|
|
242
320
|
when rendering them in a Story
|
|
243
|
-
|
|
244
|
-
#### `slotTestingDummyFactory`
|
|
245
|
-
|
|
246
|
-
This is not relevant if using the render-view-component approach. But useful if you
|
|
247
|
-
are planning on rendering the view using the xstate-tree machine itself, or testing the machine
|
|
248
|
-
via the view.
|
|
249
|
-
|
|
250
|
-
It's a simple function that takes a name argument and returns a basic xstate-tree machine that you
|
|
251
|
-
can replace slot services with. It just renders a div containing the name supplied
|
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
|
*
|
|
@@ -64,11 +74,19 @@ exports.viewToMachine = viewToMachine;
|
|
|
64
74
|
* @returns an xstate-tree machine that will render the right machines based on the routing events
|
|
65
75
|
*/
|
|
66
76
|
function buildRoutingMachine(_routes, mappings) {
|
|
77
|
+
/**
|
|
78
|
+
* States in xstate can't contain dots, since the states are named after the routing events
|
|
79
|
+
* if the routing event contains a dot that will make a state with a dot in it
|
|
80
|
+
* this function sanitizes the event name to remove dots and is used for the state names and targets
|
|
81
|
+
*/
|
|
82
|
+
function sanitizeEventName(event) {
|
|
83
|
+
return event.replace(/\.([a-zA-Z])/g, (_, letter) => letter.toUpperCase());
|
|
84
|
+
}
|
|
67
85
|
const contentSlot = (0, slots_1.singleSlot)("Content");
|
|
68
86
|
const mappingsToStates = Object.entries(mappings).reduce((acc, [event, _machine]) => {
|
|
69
87
|
return {
|
|
70
88
|
...acc,
|
|
71
|
-
[event]: {
|
|
89
|
+
[sanitizeEventName(event)]: {
|
|
72
90
|
invoke: {
|
|
73
91
|
src: event,
|
|
74
92
|
id: contentSlot.getId(),
|
|
@@ -79,7 +97,7 @@ function buildRoutingMachine(_routes, mappings) {
|
|
|
79
97
|
const mappingsToEvents = Object.keys(mappings).reduce((acc, event) => ({
|
|
80
98
|
...acc,
|
|
81
99
|
[event]: {
|
|
82
|
-
target: `.${event}`,
|
|
100
|
+
target: `.${sanitizeEventName(event)}`,
|
|
83
101
|
},
|
|
84
102
|
}), {});
|
|
85
103
|
const machine = (0, xstate_1.setup)({
|
package/lib/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.lazy = exports.loggingMetaOptions = exports.TestRoutingContext = exports.useActiveRouteEvents = exports.useRouteArgsIfActive = exports.useIsRouteActive = exports.matchRoute = exports.buildCreateRoute = exports.Link = exports.genericSlotsTestingDummy = exports.onBroadcast = exports.buildRootComponent = exports.broadcast = void 0;
|
|
17
|
+
exports.lazy = exports.loggingMetaOptions = exports.useOnRoute = exports.TestRoutingContext = exports.useActiveRouteEvents = exports.useRouteArgsIfActive = exports.useIsRouteActive = exports.matchRoute = exports.buildCreateRoute = exports.Link = exports.genericSlotsTestingDummy = exports.onBroadcast = exports.buildRootComponent = exports.broadcast = void 0;
|
|
18
18
|
__exportStar(require("./builders"), exports);
|
|
19
19
|
__exportStar(require("./slots"), exports);
|
|
20
20
|
var xstateTree_1 = require("./xstateTree");
|
|
@@ -32,6 +32,7 @@ Object.defineProperty(exports, "useIsRouteActive", { enumerable: true, get: func
|
|
|
32
32
|
Object.defineProperty(exports, "useRouteArgsIfActive", { enumerable: true, get: function () { return routing_1.useRouteArgsIfActive; } });
|
|
33
33
|
Object.defineProperty(exports, "useActiveRouteEvents", { enumerable: true, get: function () { return routing_1.useActiveRouteEvents; } });
|
|
34
34
|
Object.defineProperty(exports, "TestRoutingContext", { enumerable: true, get: function () { return routing_1.TestRoutingContext; } });
|
|
35
|
+
Object.defineProperty(exports, "useOnRoute", { enumerable: true, get: function () { return routing_1.useOnRoute; } });
|
|
35
36
|
var useService_1 = require("./useService");
|
|
36
37
|
Object.defineProperty(exports, "loggingMetaOptions", { enumerable: true, get: function () { return useService_1.loggingMetaOptions; } });
|
|
37
38
|
var lazy_1 = require("./lazy");
|
|
@@ -69,7 +69,7 @@ function buildCreateRoute(history, basePath) {
|
|
|
69
69
|
}
|
|
70
70
|
return parentRoutes;
|
|
71
71
|
}
|
|
72
|
-
return ({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, }) => {
|
|
72
|
+
return ({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, canMatch, }) => {
|
|
73
73
|
let fullParamsSchema = paramsSchema;
|
|
74
74
|
let parentRoute = baseRoute;
|
|
75
75
|
while (fullParamsSchema && parentRoute) {
|
|
@@ -86,6 +86,7 @@ function buildCreateRoute(history, basePath) {
|
|
|
86
86
|
querySchema,
|
|
87
87
|
parent: baseRoute,
|
|
88
88
|
redirect,
|
|
89
|
+
canMatch,
|
|
89
90
|
matcher: matcher,
|
|
90
91
|
reverser: reverser,
|
|
91
92
|
// @ts-ignore :cry:
|
|
@@ -132,6 +133,16 @@ function buildCreateRoute(history, basePath) {
|
|
|
132
133
|
if (querySchema) {
|
|
133
134
|
querySchema.parse(matches.query);
|
|
134
135
|
}
|
|
136
|
+
// Check canMatch predicate if provided
|
|
137
|
+
if (canMatch) {
|
|
138
|
+
const canMatchResult = canMatch({
|
|
139
|
+
params: fullParams,
|
|
140
|
+
query: matches.query ?? {},
|
|
141
|
+
});
|
|
142
|
+
if (!canMatchResult) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
135
146
|
return {
|
|
136
147
|
originalUrl: `${fullUrl}${search}`,
|
|
137
148
|
type: event,
|
package/lib/routing/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useActiveRouteEvents = exports.useInRoutingContext = exports.TestRoutingContext = exports.RoutingContext = exports.useRouteArgsIfActive = exports.useIsRouteActive = exports.handleLocationChange = exports.matchRoute = exports.Link = exports.joinRoutes = exports.buildCreateRoute = void 0;
|
|
3
|
+
exports.useActiveRouteEvents = exports.useInTestRoutingContext = exports.useInRoutingContext = exports.TestRoutingContext = exports.RoutingContext = exports.useOnRoute = exports.useRouteArgsIfActive = exports.useIsRouteActive = exports.handleLocationChange = exports.matchRoute = exports.Link = exports.joinRoutes = exports.buildCreateRoute = void 0;
|
|
4
4
|
var createRoute_1 = require("./createRoute");
|
|
5
5
|
Object.defineProperty(exports, "buildCreateRoute", { enumerable: true, get: function () { return createRoute_1.buildCreateRoute; } });
|
|
6
6
|
var joinRoutes_1 = require("./joinRoutes");
|
|
@@ -15,8 +15,11 @@ var useIsRouteActive_1 = require("./useIsRouteActive");
|
|
|
15
15
|
Object.defineProperty(exports, "useIsRouteActive", { enumerable: true, get: function () { return useIsRouteActive_1.useIsRouteActive; } });
|
|
16
16
|
var useRouteArgsIfActive_1 = require("./useRouteArgsIfActive");
|
|
17
17
|
Object.defineProperty(exports, "useRouteArgsIfActive", { enumerable: true, get: function () { return useRouteArgsIfActive_1.useRouteArgsIfActive; } });
|
|
18
|
+
var useOnRoute_1 = require("./useOnRoute");
|
|
19
|
+
Object.defineProperty(exports, "useOnRoute", { enumerable: true, get: function () { return useOnRoute_1.useOnRoute; } });
|
|
18
20
|
var providers_1 = require("./providers");
|
|
19
21
|
Object.defineProperty(exports, "RoutingContext", { enumerable: true, get: function () { return providers_1.RoutingContext; } });
|
|
20
22
|
Object.defineProperty(exports, "TestRoutingContext", { enumerable: true, get: function () { return providers_1.TestRoutingContext; } });
|
|
21
23
|
Object.defineProperty(exports, "useInRoutingContext", { enumerable: true, get: function () { return providers_1.useInRoutingContext; } });
|
|
24
|
+
Object.defineProperty(exports, "useInTestRoutingContext", { enumerable: true, get: function () { return providers_1.useInTestRoutingContext; } });
|
|
22
25
|
Object.defineProperty(exports, "useActiveRouteEvents", { enumerable: true, get: function () { return providers_1.useActiveRouteEvents; } });
|
package/lib/routing/providers.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TestRoutingContext = exports.useActiveRouteEvents = exports.useInRoutingContext = exports.RoutingContext = void 0;
|
|
6
|
+
exports.TestRoutingContext = exports.useActiveRouteEvents = exports.useInTestRoutingContext = exports.useInRoutingContext = exports.RoutingContext = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const react_2 = require("react");
|
|
9
9
|
exports.RoutingContext = (0, react_2.createContext)(undefined);
|
|
@@ -22,6 +22,14 @@ function useInRoutingContext() {
|
|
|
22
22
|
return context !== undefined;
|
|
23
23
|
}
|
|
24
24
|
exports.useInRoutingContext = useInRoutingContext;
|
|
25
|
+
/**
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
function useInTestRoutingContext() {
|
|
29
|
+
const context = (0, react_2.useContext)(exports.RoutingContext);
|
|
30
|
+
return context?.isTestRoutingContext ?? false;
|
|
31
|
+
}
|
|
32
|
+
exports.useInTestRoutingContext = useInTestRoutingContext;
|
|
25
33
|
/**
|
|
26
34
|
* @public
|
|
27
35
|
*
|
|
@@ -46,6 +54,9 @@ exports.useActiveRouteEvents = useActiveRouteEvents;
|
|
|
46
54
|
* @param activeRouteEvents - The active route events to use in the context
|
|
47
55
|
*/
|
|
48
56
|
function TestRoutingContext({ activeRouteEvents, children, }) {
|
|
49
|
-
return (react_1.default.createElement(exports.RoutingContext.Provider, { value: {
|
|
57
|
+
return (react_1.default.createElement(exports.RoutingContext.Provider, { value: {
|
|
58
|
+
activeRouteEvents: { current: activeRouteEvents },
|
|
59
|
+
isTestRoutingContext: true,
|
|
60
|
+
} }, children));
|
|
50
61
|
}
|
|
51
62
|
exports.TestRoutingContext = TestRoutingContext;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useOnRoute = void 0;
|
|
4
|
+
const providers_1 = require("./providers");
|
|
5
|
+
/**
|
|
6
|
+
* @public
|
|
7
|
+
* Accepts a single Route and returns true if the route is currently active and marked as an index route.
|
|
8
|
+
* False if not.
|
|
9
|
+
*
|
|
10
|
+
* If used outside of a RoutingContext, an error will be thrown.
|
|
11
|
+
* @param route - the route to check
|
|
12
|
+
* @returns true if the route is active and an index route, false if not
|
|
13
|
+
* @throws if used outside of an xstate-tree root
|
|
14
|
+
*/
|
|
15
|
+
function useOnRoute(route) {
|
|
16
|
+
const activeRouteEvents = (0, providers_1.useActiveRouteEvents)();
|
|
17
|
+
if (!activeRouteEvents) {
|
|
18
|
+
throw new Error("useOnRoute must be used within a RoutingContext. Are you using it outside of an xstate-tree Root?");
|
|
19
|
+
}
|
|
20
|
+
return activeRouteEvents.some((activeRouteEvent) => activeRouteEvent.type === route.event &&
|
|
21
|
+
activeRouteEvent.meta?.indexEvent === true);
|
|
22
|
+
}
|
|
23
|
+
exports.useOnRoute = useOnRoute;
|
package/lib/utils.js
CHANGED
|
@@ -121,9 +121,12 @@ function mergeMeta(meta) {
|
|
|
121
121
|
}, {});
|
|
122
122
|
}
|
|
123
123
|
exports.mergeMeta = mergeMeta;
|
|
124
|
-
function getCircularReplacer() {
|
|
124
|
+
function getCircularReplacer(stripKeys) {
|
|
125
125
|
const seen = new WeakSet();
|
|
126
126
|
return (key, value) => {
|
|
127
|
+
if (stripKeys.includes(key)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
127
130
|
if (typeof value === "object" && value !== null) {
|
|
128
131
|
if (seen.has(value)) {
|
|
129
132
|
// Circular reference found, discard key
|
|
@@ -135,7 +138,7 @@ function getCircularReplacer() {
|
|
|
135
138
|
return value;
|
|
136
139
|
};
|
|
137
140
|
}
|
|
138
|
-
function toJSON(value) {
|
|
139
|
-
return JSON.parse(JSON.stringify(value, getCircularReplacer()));
|
|
141
|
+
function toJSON(value, stripKeys = []) {
|
|
142
|
+
return JSON.parse(JSON.stringify(value, getCircularReplacer(stripKeys)));
|
|
140
143
|
}
|
|
141
144
|
exports.toJSON = toJSON;
|
package/lib/xstate-tree.d.ts
CHANGED
|
@@ -45,12 +45,13 @@ export declare type AnyRoute = {
|
|
|
45
45
|
matcher: (url: string, query: ParsedQuery<string> | undefined) => any;
|
|
46
46
|
reverser: any;
|
|
47
47
|
redirect?: any;
|
|
48
|
+
canMatch?: any;
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
52
|
* @public
|
|
52
53
|
*/
|
|
53
|
-
export declare type AnyXstateTreeMachine = XstateTreeMachine<AnyStateMachine>;
|
|
54
|
+
export declare type AnyXstateTreeMachine = XstateTreeMachine<AnyStateMachine, any, any, any[]>;
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
57
|
* @public
|
|
@@ -91,6 +92,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
91
92
|
meta?: TMeta | undefined;
|
|
92
93
|
redirect?: RouteRedirect<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta> | undefined;
|
|
93
94
|
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>>> | undefined;
|
|
95
|
+
canMatch?: RouteArgumentFunctions<boolean, MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta>> | undefined;
|
|
94
96
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, TEvent, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta>;
|
|
95
97
|
route<TBaseRoute_1 extends AnyRoute>(baseRoute?: TBaseRoute_1 | undefined): <TEvent_1 extends string, TParamsSchema_1 extends Z.ZodObject<any, "strip", Z.ZodTypeAny, {
|
|
96
98
|
[x: string]: any;
|
|
@@ -100,7 +102,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
100
102
|
[x: string]: any;
|
|
101
103
|
}, {
|
|
102
104
|
[x: string]: any;
|
|
103
|
-
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, }: {
|
|
105
|
+
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, canMatch, }: {
|
|
104
106
|
event: TEvent_1;
|
|
105
107
|
paramsSchema?: TParamsSchema_1 | undefined;
|
|
106
108
|
querySchema?: TQuerySchema_1 | undefined;
|
|
@@ -122,6 +124,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
122
124
|
*/
|
|
123
125
|
reverser: RouteArgumentFunctions<string, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>>;
|
|
124
126
|
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>> | undefined;
|
|
127
|
+
canMatch?: RouteArgumentFunctions<boolean, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1> & SharedMeta, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1> & SharedMeta>> | undefined;
|
|
125
128
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, TEvent_1, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1> & SharedMeta>;
|
|
126
129
|
};
|
|
127
130
|
|
|
@@ -136,7 +139,9 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
136
139
|
export declare function buildRootComponent<TMachine extends AnyXstateTreeMachine>(options: {
|
|
137
140
|
machine: TMachine;
|
|
138
141
|
} & MarkOptionalLikePropertiesOptional<RootOptions<InputFrom<TMachine>>>): {
|
|
139
|
-
(
|
|
142
|
+
({ children, }: {
|
|
143
|
+
children?: React_2.ReactNode;
|
|
144
|
+
}): JSX.Element;
|
|
140
145
|
rootMachine: TMachine;
|
|
141
146
|
};
|
|
142
147
|
|
|
@@ -329,7 +334,7 @@ declare type OmitOptional<T> = {
|
|
|
329
334
|
*/
|
|
330
335
|
export declare function onBroadcast(handler: (event: GlobalEvents) => void): () => void;
|
|
331
336
|
|
|
332
|
-
declare type Options<TStateMachine extends
|
|
337
|
+
declare type Options<TStateMachine extends AnyXstateTreeMachine> = {
|
|
333
338
|
/**
|
|
334
339
|
* Displayed while the promise is resolving, defaults to returning null
|
|
335
340
|
*/
|
|
@@ -370,6 +375,14 @@ export declare type Query<T> = T extends {
|
|
|
370
375
|
query: infer TQuery;
|
|
371
376
|
} ? TQuery : undefined;
|
|
372
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Repairs the return type of the `provide` function on XstateTreeMachines to correctly return
|
|
380
|
+
* an XstateTreeMachine type instead of an xstate StateMachine
|
|
381
|
+
*/
|
|
382
|
+
declare type RepairProvideReturnType<T extends AnyStateMachine, TSelectorsOutput, TActionsOutput, TSlots extends readonly Slot[]> = {
|
|
383
|
+
[K in keyof T]: K extends "provide" ? (...args: Parameters<T[K]>) => XstateTreeMachine<T, TSelectorsOutput, TActionsOutput, TSlots> : T[K];
|
|
384
|
+
};
|
|
385
|
+
|
|
373
386
|
declare type ResolveZodType<T extends Z.ZodType<any> | undefined> = undefined extends T ? undefined : Z.TypeOf<Exclude<T, undefined>>;
|
|
374
387
|
|
|
375
388
|
declare type Return<TRoutes extends Route<any, any, any, any>[]> = {
|
|
@@ -464,6 +477,12 @@ export declare type Route<TParams, TQuery, TEvent, TMeta> = {
|
|
|
464
477
|
paramsSchema?: Z.ZodObject<any>;
|
|
465
478
|
querySchema?: Z.ZodObject<any>;
|
|
466
479
|
redirect?: RouteRedirect<TParams, TQuery, TMeta>;
|
|
480
|
+
/**
|
|
481
|
+
* Optional predicate to control whether this route can be matched.
|
|
482
|
+
* Called after URL matching but before the route is considered matched.
|
|
483
|
+
* Useful for access control or conditional routing.
|
|
484
|
+
*/
|
|
485
|
+
canMatch?: RouteArgumentFunctions<boolean, TParams, TQuery, TMeta>;
|
|
467
486
|
};
|
|
468
487
|
|
|
469
488
|
/**
|
|
@@ -661,6 +680,18 @@ export declare function useActiveRouteEvents(): {
|
|
|
661
680
|
*/
|
|
662
681
|
export declare function useIsRouteActive(...routes: AnyRoute[]): boolean;
|
|
663
682
|
|
|
683
|
+
/**
|
|
684
|
+
* @public
|
|
685
|
+
* Accepts a single Route and returns true if the route is currently active and marked as an index route.
|
|
686
|
+
* False if not.
|
|
687
|
+
*
|
|
688
|
+
* If used outside of a RoutingContext, an error will be thrown.
|
|
689
|
+
* @param route - the route to check
|
|
690
|
+
* @returns true if the route is active and an index route, false if not
|
|
691
|
+
* @throws if used outside of an xstate-tree root
|
|
692
|
+
*/
|
|
693
|
+
export declare function useOnRoute(route: AnyRoute): boolean;
|
|
694
|
+
|
|
664
695
|
/**
|
|
665
696
|
* @public
|
|
666
697
|
* Returns the arguments for the given route if the route is active.
|
|
@@ -691,6 +722,7 @@ export declare type View<TActionsOutput, TSelectorsOutput, TSlots extends readon
|
|
|
691
722
|
slots: Record<GetSlotNames<TSlots>, React_2.ComponentType>;
|
|
692
723
|
actions: TActionsOutput;
|
|
693
724
|
selectors: TSelectorsOutput;
|
|
725
|
+
children?: React_2.ReactNode;
|
|
694
726
|
}>;
|
|
695
727
|
|
|
696
728
|
/**
|
|
@@ -701,7 +733,7 @@ export declare type View<TActionsOutput, TSelectorsOutput, TSlots extends readon
|
|
|
701
733
|
* @param view - the React view you want to invoke in an xstate machine
|
|
702
734
|
* @returns The view wrapped into an xstate-tree machine, ready to be invoked by other xstate machines or used with `buildRootComponent`
|
|
703
735
|
*/
|
|
704
|
-
export declare function viewToMachine(view: () => JSX.Element): AnyXstateTreeMachine;
|
|
736
|
+
export declare function viewToMachine(view: (args?: any) => JSX.Element | null): AnyXstateTreeMachine;
|
|
705
737
|
|
|
706
738
|
declare type WithParentPath<TCurrent extends string, TParentPath extends string> = `${TParentPath extends "" ? "" : `${TParentPath}.`}${TCurrent}`;
|
|
707
739
|
|
|
@@ -716,7 +748,7 @@ export declare type XstateTreeHistory<T = unknown> = History_2<{
|
|
|
716
748
|
/**
|
|
717
749
|
* @public
|
|
718
750
|
*/
|
|
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>;
|
|
751
|
+
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>;
|
|
720
752
|
|
|
721
753
|
/**
|
|
722
754
|
* @internal
|
package/lib/xstateTree.js
CHANGED
|
@@ -32,7 +32,6 @@ const fast_memoize_1 = __importDefault(require("fast-memoize"));
|
|
|
32
32
|
const react_2 = __importStar(require("react"));
|
|
33
33
|
const tiny_emitter_1 = require("tiny-emitter");
|
|
34
34
|
const routing_1 = require("./routing");
|
|
35
|
-
const providers_1 = require("./routing/providers");
|
|
36
35
|
const useConstant_1 = require("./useConstant");
|
|
37
36
|
const useService_1 = require("./useService");
|
|
38
37
|
const utils_1 = require("./utils");
|
|
@@ -69,8 +68,8 @@ interpreter) {
|
|
|
69
68
|
return interpreter.sessionId;
|
|
70
69
|
}
|
|
71
70
|
const getViewForInterpreter = (0, fast_memoize_1.default)((interpreter) => {
|
|
72
|
-
return react_2.default.memo(function InterpreterView() {
|
|
73
|
-
const activeRouteEvents = (0,
|
|
71
|
+
return react_2.default.memo(function InterpreterView({ children, }) {
|
|
72
|
+
const activeRouteEvents = (0, routing_1.useActiveRouteEvents)();
|
|
74
73
|
(0, react_2.useEffect)(() => {
|
|
75
74
|
if (activeRouteEvents) {
|
|
76
75
|
activeRouteEvents.forEach((event) => {
|
|
@@ -80,7 +79,7 @@ const getViewForInterpreter = (0, fast_memoize_1.default)((interpreter) => {
|
|
|
80
79
|
});
|
|
81
80
|
}
|
|
82
81
|
}, []);
|
|
83
|
-
return react_2.default.createElement(XstateTreeView, { actor: interpreter });
|
|
82
|
+
return react_2.default.createElement(XstateTreeView, { actor: interpreter }, children);
|
|
84
83
|
});
|
|
85
84
|
},
|
|
86
85
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -105,7 +104,7 @@ function useSlots(interpreter, slots) {
|
|
|
105
104
|
return slots.reduce((views, slot) => {
|
|
106
105
|
return {
|
|
107
106
|
...views,
|
|
108
|
-
[slot]: () => {
|
|
107
|
+
[slot]: (({ children: reactChildren }) => {
|
|
109
108
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
110
109
|
const [__, children] = (0, useService_1.useService)(interpreter);
|
|
111
110
|
if (slot.toString().endsWith("Multi")) {
|
|
@@ -116,26 +115,25 @@ function useSlots(interpreter, slots) {
|
|
|
116
115
|
const interpreterForSlot = children[`${slot.toLowerCase()}-slot`];
|
|
117
116
|
if (interpreterForSlot) {
|
|
118
117
|
const View = getViewForInterpreter(interpreterForSlot);
|
|
119
|
-
return react_2.default.createElement(View, null);
|
|
118
|
+
return react_2.default.createElement(View, null, reactChildren);
|
|
120
119
|
}
|
|
121
120
|
else {
|
|
122
121
|
// Waiting for the interpreter for this slot to be invoked
|
|
123
122
|
return null;
|
|
124
123
|
}
|
|
125
124
|
}
|
|
126
|
-
},
|
|
125
|
+
}),
|
|
127
126
|
};
|
|
128
127
|
}, {});
|
|
129
128
|
});
|
|
130
129
|
}
|
|
131
130
|
function XstateTreeMultiSlotView({ childInterpreters, }) {
|
|
132
|
-
console.log("XstateTreeMultiSlotView", childInterpreters);
|
|
133
131
|
return (react_2.default.createElement(react_2.default.Fragment, null, childInterpreters.map((i) => (react_2.default.createElement(XstateTreeView, { key: i.id, actor: i })))));
|
|
134
132
|
}
|
|
135
133
|
/**
|
|
136
134
|
* @internal
|
|
137
135
|
*/
|
|
138
|
-
function XstateTreeView({ actor }) {
|
|
136
|
+
function XstateTreeView({ actor, children }) {
|
|
139
137
|
const [current] = (0, useService_1.useService)(actor);
|
|
140
138
|
const currentRef = (0, react_2.useRef)(current);
|
|
141
139
|
currentRef.current = current;
|
|
@@ -175,7 +173,7 @@ function XstateTreeView({ actor }) {
|
|
|
175
173
|
inState: inState,
|
|
176
174
|
meta: (0, utils_1.mergeMeta)(current.getMeta()),
|
|
177
175
|
});
|
|
178
|
-
return (react_2.default.createElement(View, { selectors: selectorsRef.current, actions: actions, slots: slots }));
|
|
176
|
+
return (react_2.default.createElement(View, { selectors: selectorsRef.current, actions: actions, slots: slots }, children));
|
|
179
177
|
}
|
|
180
178
|
exports.XstateTreeView = XstateTreeView;
|
|
181
179
|
/**
|
|
@@ -211,7 +209,7 @@ function buildRootComponent(options) {
|
|
|
211
209
|
if (!machine._xstateTree.View) {
|
|
212
210
|
throw new Error("Root machine has no associated view");
|
|
213
211
|
}
|
|
214
|
-
const RootComponent = function XstateTreeRootComponent() {
|
|
212
|
+
const RootComponent = function XstateTreeRootComponent({ children, }) {
|
|
215
213
|
const lastSnapshotsRef = (0, react_2.useRef)({});
|
|
216
214
|
const [_, __, interpreter] = (0, react_1.useActor)(machine, {
|
|
217
215
|
input,
|
|
@@ -221,15 +219,20 @@ function buildRootComponent(options) {
|
|
|
221
219
|
console.log(`[xstate-tree] actor spawned: ${event.actorRef.id}`);
|
|
222
220
|
break;
|
|
223
221
|
case "@xstate.event":
|
|
222
|
+
// Ignore internal events
|
|
223
|
+
if (event.event.type.includes("xstate.")) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
224
226
|
console.log(`[xstate-tree] event: ${event.sourceRef ? event.sourceRef.id : "UNKNOWN"} -> ${event.event.type} -> ${event.actorRef.id}`, event.event);
|
|
225
227
|
break;
|
|
226
228
|
case "@xstate.snapshot":
|
|
227
229
|
const lastSnapshot = lastSnapshotsRef.current[event.actorRef.sessionId];
|
|
230
|
+
const strippedKeys = ["_subscription"];
|
|
228
231
|
if (!lastSnapshot) {
|
|
229
|
-
console.log(`[xstate-tree] initial snapshot: ${event.actorRef.id}`, (0, utils_1.toJSON)(event.snapshot));
|
|
232
|
+
console.log(`[xstate-tree] initial snapshot: ${event.actorRef.id}`, (0, utils_1.toJSON)(event.snapshot, strippedKeys));
|
|
230
233
|
}
|
|
231
234
|
else {
|
|
232
|
-
console.log(`[xstate-tree] snapshot: ${event.actorRef.id} transitioning to`, (0, utils_1.toJSON)(event.snapshot), "from", (0, utils_1.toJSON)(lastSnapshot));
|
|
235
|
+
console.log(`[xstate-tree] snapshot: ${event.actorRef.id} transitioning to`, (0, utils_1.toJSON)(event.snapshot, strippedKeys), "from", (0, utils_1.toJSON)(lastSnapshot, strippedKeys));
|
|
233
236
|
}
|
|
234
237
|
lastSnapshotsRef.current[event.actorRef.sessionId] = event.snapshot;
|
|
235
238
|
break;
|
|
@@ -243,7 +246,10 @@ function buildRootComponent(options) {
|
|
|
243
246
|
activeRouteEventsRef.current = events;
|
|
244
247
|
};
|
|
245
248
|
const insideRoutingContext = (0, routing_1.useInRoutingContext)();
|
|
246
|
-
|
|
249
|
+
const inTestRoutingContext = (0, routing_1.useInTestRoutingContext)();
|
|
250
|
+
if (!inTestRoutingContext &&
|
|
251
|
+
insideRoutingContext &&
|
|
252
|
+
typeof routing !== "undefined") {
|
|
247
253
|
const m = "Routing root rendered inside routing context, this implies a bug";
|
|
248
254
|
if (process.env.NODE_ENV !== "production") {
|
|
249
255
|
throw new Error(m);
|
|
@@ -363,10 +369,10 @@ function buildRootComponent(options) {
|
|
|
363
369
|
}, [activeRoute]);
|
|
364
370
|
if (routingProviderValue) {
|
|
365
371
|
return (react_2.default.createElement(routing_1.RoutingContext.Provider, { value: routingProviderValue },
|
|
366
|
-
react_2.default.createElement(XstateTreeView, { actor: interpreter })));
|
|
372
|
+
react_2.default.createElement(XstateTreeView, { actor: interpreter }, children)));
|
|
367
373
|
}
|
|
368
374
|
else {
|
|
369
|
-
return react_2.default.createElement(XstateTreeView, { actor: interpreter });
|
|
375
|
+
return react_2.default.createElement(XstateTreeView, { actor: interpreter }, children);
|
|
370
376
|
}
|
|
371
377
|
};
|
|
372
378
|
RootComponent.rootMachine = machine;
|
package/package.json
CHANGED