Skip to content

Commit a8aa4ac

Browse files
authored
feat: add .send() API (#67)
1 parent b24ef25 commit a8aa4ac

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

.changeset/honest-singers-do.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"xstate-component-tree": minor
3+
---
4+
5+
Added `.send()` API
6+
7+
The `.send()` API is a simple passthrough to the interpreter for the root statechart being managed by `xstate-component-tree`, and is intended as a convenience function to make it easier to interact with a `ComponentTree` instance instead of a direct XState `Interpreter` reference.
8+
9+
[XState Docs on .send()](https://xstate.js.org/docs/guides/interpretation.html#sending-events)

src/component-tree.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,16 @@ class ComponentTree {
504504
return [ ...this._services.values() ].some(({ state }) => state.matches(path));
505505
}
506506

507+
/**
508+
* Send an event to the root machine only
509+
*
510+
* @param {...any} event Event to send
511+
* @returns Updated XState State object
512+
*/
513+
send(...event) {
514+
return this._services.get(this.id).interpreter.send(...event);
515+
}
516+
507517
/**
508518
* Provides an observable API, matches the svelte store contract
509519
* https://svelte.dev/docs#component-format-script-4-prefix-stores-with-$-to-access-their-values-store-contract

tests/api/send.test.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as assert from "uvu/assert";
2+
3+
import describe from "../util/describe.js";
4+
import { createTree, waitForPath } from "../util/trees.js";
5+
import { treeTeardown } from "../util/context.js";
6+
import { diff } from "../util/snapshot.js";
7+
8+
import single from "./specimens/single.js";
9+
import child from "./specimens/child.js";
10+
11+
describe("send", (it) => {
12+
it.after.each(treeTeardown);
13+
14+
it("should be a callable method", async (context) => {
15+
const tree = context.tree = createTree(single);
16+
17+
assert.type(tree.builder.send, "function");
18+
});
19+
20+
it("should send to the root tree", async (context) => {
21+
const tree = context.tree = createTree(single);
22+
23+
const { tree : one } = await tree();
24+
25+
tree.builder.send("NEXT");
26+
27+
const { tree : two } = await waitForPath(tree, "two");
28+
29+
diff(one, two, `
30+
[
31+
[Object: null prototype] {
32+
Actual:
33+
-- path: "one",
34+
-- component: [Function: one],
35+
Expected:
36+
++ path: "two",
37+
++ component: [Function: two],
38+
props: false,
39+
children: []
40+
}
41+
]`);
42+
});
43+
44+
it("should *not* send to child trees", async (context) => {
45+
const tree = context.tree = createTree(child);
46+
47+
const { tree : one } = await tree();
48+
49+
tree.builder.send("NEXT");
50+
51+
const { tree : two } = await waitForPath(tree, "root.two");
52+
53+
diff(one, two, `
54+
[
55+
[Object: null prototype] {
56+
Actual:
57+
-- path: "root.one",
58+
-- component: [Function: one],
59+
Expected:
60+
++ path: "root.two",
61+
++ component: [Function: two],
62+
props: false,
63+
children: []
64+
},
65+
[Object: null prototype] {
66+
path: "child.one",
67+
component: [Function: child-one],
68+
props: false,
69+
children: []
70+
}
71+
]`);
72+
});
73+
});

0 commit comments

Comments
 (0)