Skip to content

Commit

Permalink
fix(builders): buildRoutingMachine not working with routing events co…
Browse files Browse the repository at this point in the history
…ntaining dots
  • Loading branch information
UberMouse committed Aug 15, 2024
1 parent 70607bb commit 3a7fe9c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 11 deletions.
52 changes: 43 additions & 9 deletions src/builders.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,15 @@ describe("xstate-tree builders", () => {
const hist: XstateTreeHistory = createMemoryHistory();
const createRoute = buildCreateRoute(() => hist, "/");

const fooRoute = createRoute.simpleRoute()({
url: "/foo/",
event: "GO_TO_FOO",
});
const barRoute = createRoute.simpleRoute()({
url: "/bar/",
event: "GO_TO_BAR",
});

it("takes a mapping of routes to machines and returns a machine that invokes those machines when those routes events are broadcast", async () => {
const fooRoute = createRoute.simpleRoute()({
url: "/foo/",
event: "GO_TO_FOO",
});
const barRoute = createRoute.simpleRoute()({
url: "/bar/",
event: "GO_TO_BAR",
});
const FooMachine = viewToMachine(() => <div>foo</div>);
const BarMachine = viewToMachine(() => <div>bar</div>);

Expand All @@ -142,5 +141,40 @@ describe("xstate-tree builders", () => {
act(() => barRoute.navigate());
await waitFor(() => getByText("bar"));
});

it("handles routing events that contain . in them", async () => {
const fooRoute = createRoute.simpleRoute()({
url: "/foo/",
event: "routing.foo",
});
const barRoute = createRoute.simpleRoute()({
url: "/bar/",
event: "routing.bar",
});
const FooMachine = viewToMachine(() => <div>foo</div>);
const BarMachine = viewToMachine(() => <div>bar</div>);

const routingMachine = buildRoutingMachine([fooRoute, barRoute], {
"routing.foo": FooMachine,
"routing.bar": BarMachine,
});

const Root = buildRootComponent({
machine: routingMachine,
routing: {
history: hist,
basePath: "/",
routes: [fooRoute, barRoute],
},
});

const { getByText } = render(<Root />);

act(() => fooRoute.navigate());
await waitFor(() => getByText("foo"));

act(() => barRoute.navigate());
await waitFor(() => getByText("bar"));
});
});
});
13 changes: 11 additions & 2 deletions src/builders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,22 @@ export function buildRoutingMachine<TRoutes extends AnyRoute[]>(
_routes: TRoutes,
mappings: Record<TRoutes[number]["event"], AnyXstateTreeMachine>
): AnyXstateTreeMachine {
/**
* States in xstate can't contain dots, since the states are named after the routing events
* if the routing event contains a dot that will make a state with a dot in it
* this function sanitizes the event name to remove dots and is used for the state names and targets
*/
function sanitizeEventName(event: string) {
return event.replace(/\.([a-zA-Z])/g, (_, letter) => letter.toUpperCase());
}

const contentSlot = singleSlot("Content");
const mappingsToStates = Object.entries<AnyXstateTreeMachine>(
mappings
).reduce((acc, [event, _machine]) => {
return {
...acc,
[event]: {
[sanitizeEventName(event)]: {
invoke: {
src: event,
id: contentSlot.getId(),
Expand All @@ -130,7 +139,7 @@ export function buildRoutingMachine<TRoutes extends AnyRoute[]>(
(acc, event) => ({
...acc,
[event]: {
target: `.${event}`,
target: `.${sanitizeEventName(event)}`,
},
}),
{}
Expand Down

0 comments on commit 3a7fe9c

Please sign in to comment.