diff --git a/.eslintignore b/.eslintignore
index 1e41797..6c6501a 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
*.snap
+*.typegen.ts
README.md
\ No newline at end of file
diff --git a/src/builders.spec.tsx b/src/builders.spec.tsx
new file mode 100644
index 0000000..c0be825
--- /dev/null
+++ b/src/builders.spec.tsx
@@ -0,0 +1,18 @@
+import { render, waitFor } from "@testing-library/react";
+import React from "react";
+
+import { viewToMachine } from "./builders";
+import { buildRootComponent } from "./xstateTree";
+
+describe("xstate-tree builders", () => {
+ describe("viewToMachine", () => {
+ it("takes a React view and wraps it in an xstate-tree machine that renders that view", async () => {
+ const ViewMachine = viewToMachine(() =>
hello world
);
+ const Root = buildRootComponent(ViewMachine);
+
+ const { getByText } = render();
+
+ await waitFor(() => getByText("hello world"));
+ });
+ });
+});
diff --git a/src/builders.ts b/src/builders.ts
index 14a57cc..319d44d 100644
--- a/src/builders.ts
+++ b/src/builders.ts
@@ -1,12 +1,13 @@
import React from "react";
-import type {
- EventObject,
- StateMachine,
- AnyStateMachine,
- ContextFrom,
- EventFrom,
- InterpreterFrom,
- AnyFunction,
+import {
+ type EventObject,
+ type StateMachine,
+ type AnyStateMachine,
+ type ContextFrom,
+ type EventFrom,
+ type InterpreterFrom,
+ type AnyFunction,
+ createMachine,
} from "xstate";
import { Slot } from "./slots";
@@ -22,6 +23,7 @@ import {
XStateTreeMachineMetaV1,
XstateTreeMachineStateSchemaV1,
XstateTreeMachineStateSchemaV2,
+ AnyXstateTreeMachine,
} from "./types";
/**
@@ -261,3 +263,20 @@ export function createXStateTreeMachine<
return machine;
}
+
+/**
+ * @public
+ *
+ * Simple utility builder to aid in integrating existing React views with xstate-tree
+ *
+ * @param view - the React view you want to invoke in an xstate machine
+ * @returns The view wrapped into an xstate-tree machine, ready to be invoked by other xstate machines or used with `buildRootComponent`
+ */
+export function viewToMachine(view: () => JSX.Element): AnyXstateTreeMachine {
+ return createXStateTreeMachine(
+ createMachine({ initial: "idle", states: { idle: {} } }),
+ {
+ View: view,
+ }
+ );
+}
diff --git a/src/test-app/AppMachine.typegen.ts b/src/test-app/AppMachine.typegen.ts
index 1d46e11..90e8106 100644
--- a/src/test-app/AppMachine.typegen.ts
+++ b/src/test-app/AppMachine.typegen.ts
@@ -1,27 +1,35 @@
-// This file was automatically generated. Edits will be overwritten
-export interface Typegen0 {
- "@@xstate/typegen": true;
- internalEvents: {
- "xstate.init": { type: "xstate.init" };
- };
- invokeSrcNameMap: {
- OtherMachine: "done.invoke.app.otherScreen:invocation[0]";
- TodosMachine: "done.invoke.app.todos:invocation[0]";
- };
- missingImplementations: {
- actions: never;
- services: never;
- guards: never;
- delays: never;
- };
- eventsCausingActions: {};
- eventsCausingServices: {
- OtherMachine: "GO_SETTINGS";
- TodosMachine: "GO_HOME";
- };
- eventsCausingGuards: {};
- eventsCausingDelays: {};
- matchesStates: "otherScreen" | "todos" | "waitingForRoute";
- tags: never;
-}
+ // This file was automatically generated. Edits will be overwritten
+
+ export interface Typegen0 {
+ '@@xstate/typegen': true;
+ internalEvents: {
+ "xstate.init": { type: "xstate.init" };
+ };
+ invokeSrcNameMap: {
+ "OtherMachine": "done.invoke.app.otherScreen:invocation[0]";
+"TodosMachine": "done.invoke.app.todos:invocation[0]";
+ };
+ missingImplementations: {
+ actions: never;
+ delays: never;
+ guards: never;
+ services: never;
+ };
+ eventsCausingActions: {
+
+ };
+ eventsCausingDelays: {
+
+ };
+ eventsCausingGuards: {
+
+ };
+ eventsCausingServices: {
+ "OtherMachine": "GO_SETTINGS";
+"TodosMachine": "GO_HOME";
+ };
+ matchesStates: "otherScreen" | "todos" | "waitingForRoute";
+ tags: never;
+ }
+
\ No newline at end of file
diff --git a/src/xstateTree.tsx b/src/xstateTree.tsx
index fda1a1e..c3bbb5b 100644
--- a/src/xstateTree.tsx
+++ b/src/xstateTree.tsx
@@ -78,6 +78,7 @@ const getViewForInterpreter = memoize(
useEffect(() => {
if (activeRouteEvents) {
activeRouteEvents.forEach((event) => {
+ // @ts-ignore fixed in v5 branch
if (interpreter.state.nextEvents.includes(event.type)) {
interpreter.send(event);
}
diff --git a/xstate-tree.api.md b/xstate-tree.api.md
index d34658c..0a7aa3d 100644
--- a/xstate-tree.api.md
+++ b/xstate-tree.api.md
@@ -5,7 +5,7 @@
```ts
import { AnyEventObject } from 'xstate';
-import type { AnyFunction } from 'xstate';
+import { AnyFunction } from 'xstate';
import { AnyStateMachine } from 'xstate';
import { BaseActionObject } from 'xstate';
import { ComponentPropsWithRef } from 'react';
@@ -13,7 +13,7 @@ import { ContextFrom } from 'xstate';
import { EventFrom } from 'xstate';
import { EventObject } from 'xstate';
import { History as History_2 } from 'history';
-import type { InterpreterFrom } from 'xstate';
+import { InterpreterFrom } from 'xstate';
import { JSXElementConstructor } from 'react';
import { ParsedQuery } from 'query-string';
import { default as React_2 } from 'react';
@@ -439,6 +439,9 @@ export type ViewProps JSX.Element): AnyXstateTreeMachine;
+
// @public (undocumented)
export type XstateTreeHistory = History_2<{
meta?: T;