@koordinates/xstate-tree 4.2.0 → 4.3.0-beta.2

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/lib/xstateTree.js CHANGED
@@ -1,13 +1,42 @@
1
- import { useMachine } from "@xstate/react";
2
- import memoize from "fast-memoize";
3
- import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react";
4
- import { TinyEmitter } from "tiny-emitter";
5
- import { handleLocationChange, RoutingContext, } from "./routing";
6
- import { useActiveRouteEvents } from "./routing/providers";
7
- import { useConstant } from "./useConstant";
8
- import { useService } from "./useService";
9
- import { assertIsDefined, isLikelyPageLoad } from "./utils";
10
- export const emitter = new TinyEmitter();
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.buildRootComponent = exports.recursivelySend = exports.XstateTreeView = exports.getMultiSlotViewForChildren = exports.onBroadcast = exports.broadcast = exports.emitter = void 0;
30
+ const react_1 = require("@xstate/react");
31
+ const fast_memoize_1 = __importDefault(require("fast-memoize"));
32
+ const react_2 = __importStar(require("react"));
33
+ const tiny_emitter_1 = require("tiny-emitter");
34
+ const routing_1 = require("./routing");
35
+ const providers_1 = require("./routing/providers");
36
+ const useConstant_1 = require("./useConstant");
37
+ const useService_1 = require("./useService");
38
+ const utils_1 = require("./utils");
39
+ exports.emitter = new tiny_emitter_1.TinyEmitter();
11
40
  /**
12
41
  * @public
13
42
  *
@@ -15,10 +44,11 @@ export const emitter = new TinyEmitter();
15
44
  *
16
45
  * @param event - the event to broadcast
17
46
  */
18
- export function broadcast(event) {
47
+ function broadcast(event) {
19
48
  console.debug("[xstate-tree] broadcasting event ", event.type);
20
- emitter.emit("event", event);
49
+ exports.emitter.emit("event", event);
21
50
  }
51
+ exports.broadcast = broadcast;
22
52
  /**
23
53
  * @public
24
54
  *
@@ -26,21 +56,22 @@ export function broadcast(event) {
26
56
  *
27
57
  * @param handler - the handler to call when an event is broadcast
28
58
  */
29
- export function onBroadcast(handler) {
30
- emitter.on("event", handler);
59
+ function onBroadcast(handler) {
60
+ exports.emitter.on("event", handler);
31
61
  return () => {
32
- emitter.off("event", handler);
62
+ exports.emitter.off("event", handler);
33
63
  };
34
64
  }
65
+ exports.onBroadcast = onBroadcast;
35
66
  function cacheKeyForInterpreter(
36
67
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
68
  interpreter) {
38
69
  return interpreter.sessionId;
39
70
  }
40
- const getViewForInterpreter = memoize((interpreter) => {
41
- return React.memo(function InterpreterView() {
42
- const activeRouteEvents = useActiveRouteEvents();
43
- useEffect(() => {
71
+ const getViewForInterpreter = (0, fast_memoize_1.default)((interpreter) => {
72
+ return react_2.default.memo(function InterpreterView() {
73
+ const activeRouteEvents = (0, providers_1.useActiveRouteEvents)();
74
+ (0, react_2.useEffect)(() => {
44
75
  if (activeRouteEvents) {
45
76
  activeRouteEvents.forEach((event) => {
46
77
  if (interpreter.state.nextEvents.includes(event.type)) {
@@ -49,7 +80,7 @@ const getViewForInterpreter = memoize((interpreter) => {
49
80
  });
50
81
  }
51
82
  }, []);
52
- return React.createElement(XstateTreeView, { interpreter: interpreter });
83
+ return react_2.default.createElement(XstateTreeView, { interpreter: interpreter });
53
84
  });
54
85
  },
55
86
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -57,35 +88,35 @@ const getViewForInterpreter = memoize((interpreter) => {
57
88
  /**
58
89
  * @private
59
90
  */
60
- export const getMultiSlotViewForChildren = memoize((parent, slot) => {
61
- return React.memo(function MultiSlotView() {
62
- const [_, children] = useService(parent);
91
+ exports.getMultiSlotViewForChildren = (0, fast_memoize_1.default)((parent, slot) => {
92
+ return react_2.default.memo(function MultiSlotView() {
93
+ const [_, children] = (0, useService_1.useService)(parent);
63
94
  const interpreters = [...children.values()];
64
95
  // Once the interpreter is stopped, initialized gets set to false
65
96
  // We don't want to render stopped interpreters
66
97
  const interpretersWeCareAbout = interpreters.filter((i) => i.id.includes(slot) && i.initialized);
67
- return (React.createElement(XstateTreeMultiSlotView, { childInterpreters: interpretersWeCareAbout }));
98
+ return (react_2.default.createElement(XstateTreeMultiSlotView, { childInterpreters: interpretersWeCareAbout }));
68
99
  });
69
100
  }, {
70
101
  serializer: (args) => `${cacheKeyForInterpreter(args[0])}-${args[1]}`,
71
102
  });
72
103
  function useSlots(interpreter, slots) {
73
- return useConstant(() => {
104
+ return (0, useConstant_1.useConstant)(() => {
74
105
  return slots.reduce((views, slot) => {
75
106
  return {
76
107
  ...views,
77
108
  [slot]: () => {
78
109
  // eslint-disable-next-line react-hooks/rules-of-hooks
79
- const [__, children] = useService(interpreter);
110
+ const [__, children] = (0, useService_1.useService)(interpreter);
80
111
  if (slot.toString().endsWith("Multi")) {
81
- const MultiView = getMultiSlotViewForChildren(interpreter, slot.toLowerCase());
82
- return React.createElement(MultiView, null);
112
+ const MultiView = (0, exports.getMultiSlotViewForChildren)(interpreter, slot.toLowerCase());
113
+ return react_2.default.createElement(MultiView, null);
83
114
  }
84
115
  else {
85
116
  const interpreterForSlot = children.get(`${slot.toLowerCase()}-slot`);
86
117
  if (interpreterForSlot) {
87
118
  const View = getViewForInterpreter(interpreterForSlot);
88
- return React.createElement(View, null);
119
+ return react_2.default.createElement(View, null);
89
120
  }
90
121
  else {
91
122
  // Waiting for the interpreter for this slot to be invoked
@@ -98,23 +129,23 @@ function useSlots(interpreter, slots) {
98
129
  });
99
130
  }
100
131
  function XstateTreeMultiSlotView({ childInterpreters, }) {
101
- return (React.createElement(React.Fragment, null, childInterpreters.map((i) => (React.createElement(XstateTreeView, { key: i.id, interpreter: i })))));
132
+ return (react_2.default.createElement(react_2.default.Fragment, null, childInterpreters.map((i) => (react_2.default.createElement(XstateTreeView, { key: i.id, interpreter: i })))));
102
133
  }
103
134
  /**
104
135
  * @internal
105
136
  */
106
- export function XstateTreeView({ interpreter }) {
137
+ function XstateTreeView({ interpreter }) {
107
138
  var _a, _b;
108
- const [current] = useService(interpreter);
109
- const currentRef = useRef(current);
139
+ const [current] = (0, useService_1.useService)(interpreter);
140
+ const currentRef = (0, react_2.useRef)(current);
110
141
  currentRef.current = current;
111
- const selectorsRef = useRef(undefined);
142
+ const selectorsRef = (0, react_2.useRef)(undefined);
112
143
  const { slots: interpreterSlots } = interpreter.machine.meta;
113
144
  const slots = useSlots(interpreter, interpreterSlots.map((x) => x.name));
114
- const canHandleEvent = useCallback((e) => {
145
+ const canHandleEvent = (0, react_2.useCallback)((e) => {
115
146
  return interpreter.getSnapshot().can(e);
116
147
  }, [interpreter]);
117
- const inState = useCallback((state) => {
148
+ const inState = (0, react_2.useCallback)((state) => {
118
149
  var _a, _b;
119
150
  return (_b = (_a = currentRef.current) === null || _a === void 0 ? void 0 : _a.matches(state)) !== null && _b !== void 0 ? _b : false;
120
151
  },
@@ -122,7 +153,7 @@ export function XstateTreeView({ interpreter }) {
122
153
  // current state the machine is in changes. But _only_ then
123
154
  // eslint-disable-next-line react-hooks/exhaustive-deps
124
155
  [current.value]);
125
- const selectorsProxy = useConstant(() => {
156
+ const selectorsProxy = (0, useConstant_1.useConstant)(() => {
126
157
  return new Proxy({}, {
127
158
  get: (_target, prop) => {
128
159
  var _a;
@@ -130,7 +161,7 @@ export function XstateTreeView({ interpreter }) {
130
161
  },
131
162
  });
132
163
  });
133
- const actions = useConstant(() => {
164
+ const actions = (0, useConstant_1.useConstant)(() => {
134
165
  var _a;
135
166
  switch ((_a = interpreter.machine.meta) === null || _a === void 0 ? void 0 : _a.builderVersion) {
136
167
  case 1:
@@ -162,18 +193,19 @@ export function XstateTreeView({ interpreter }) {
162
193
  switch ((_b = interpreter.machine.meta) === null || _b === void 0 ? void 0 : _b.builderVersion) {
163
194
  case 1:
164
195
  const ViewV1 = interpreter.machine.meta.view;
165
- return (React.createElement(ViewV1, { selectors: selectorsRef.current, actions: actions, slots: slots, inState: inState }));
196
+ return (react_2.default.createElement(ViewV1, { selectors: selectorsRef.current, actions: actions, slots: slots, inState: inState }));
166
197
  case 2:
167
198
  const ViewV2 = interpreter.machine.meta.View;
168
- return (React.createElement(ViewV2, { selectors: selectorsRef.current, actions: actions, slots: slots }));
199
+ return (react_2.default.createElement(ViewV2, { selectors: selectorsRef.current, actions: actions, slots: slots }));
169
200
  default:
170
201
  throw new Error("builderVersion not set");
171
202
  }
172
203
  }
204
+ exports.XstateTreeView = XstateTreeView;
173
205
  /**
174
206
  * @internal
175
207
  */
176
- export function recursivelySend(service, event) {
208
+ function recursivelySend(service, event) {
177
209
  const children = ([...service.children.values()] || []).filter((s) => s.id.includes("-slot"));
178
210
  // If the service can't handle the event, don't send it
179
211
  if (service.state.nextEvents.includes(event.type)) {
@@ -186,6 +218,7 @@ export function recursivelySend(service, event) {
186
218
  }
187
219
  children.forEach((child) => recursivelySend(child, event));
188
220
  }
221
+ exports.recursivelySend = recursivelySend;
189
222
  /**
190
223
  * @public
191
224
  *
@@ -194,7 +227,7 @@ export function recursivelySend(service, event) {
194
227
  * @param machine - The root machine of the tree
195
228
  * @param routing - The routing configuration for the tree
196
229
  */
197
- export function buildRootComponent(machine, routing) {
230
+ function buildRootComponent(machine, routing) {
198
231
  if (!machine.meta) {
199
232
  throw new Error("Root machine has no meta");
200
233
  }
@@ -211,23 +244,23 @@ export function buildRootComponent(machine, routing) {
211
244
  break;
212
245
  }
213
246
  const RootComponent = function XstateTreeRootComponent() {
214
- const [_, __, interpreter] = useMachine(machine, { devTools: true });
215
- const [activeRoute, setActiveRoute] = useState(undefined);
216
- const activeRouteEventsRef = useRef([]);
217
- const [forceRenderValue, forceRender] = useState(false);
247
+ const [_, __, interpreter] = (0, react_1.useMachine)(machine, { devTools: true });
248
+ const [activeRoute, setActiveRoute] = (0, react_2.useState)(undefined);
249
+ const activeRouteEventsRef = (0, react_2.useRef)([]);
250
+ const [forceRenderValue, forceRender] = (0, react_2.useState)(false);
218
251
  const setActiveRouteEvents = (events) => {
219
252
  activeRouteEventsRef.current = events;
220
253
  };
221
- useEffect(() => {
254
+ (0, react_2.useEffect)(() => {
222
255
  function handler(event) {
223
256
  recursivelySend(interpreter, event);
224
257
  }
225
- emitter.on("event", handler);
258
+ exports.emitter.on("event", handler);
226
259
  return () => {
227
- emitter.off("event", handler);
260
+ exports.emitter.off("event", handler);
228
261
  };
229
262
  }, [interpreter]);
230
- useEffect(() => {
263
+ (0, react_2.useEffect)(() => {
231
264
  if (activeRoute === undefined) {
232
265
  return;
233
266
  }
@@ -240,7 +273,7 @@ export function buildRootComponent(machine, routing) {
240
273
  }
241
274
  const routeEventPairs = [];
242
275
  const activeRoutesEvent = activeRouteEventsRef.current.find((e) => e.type === activeRoute.event);
243
- assertIsDefined(activeRoutesEvent);
276
+ (0, utils_1.assertIsDefined)(activeRoutesEvent);
244
277
  for (let i = 0; i < routes.length; i++) {
245
278
  const route = routes[i];
246
279
  const routeEvent = activeRouteEventsRef.current[i];
@@ -250,7 +283,7 @@ export function buildRootComponent(machine, routing) {
250
283
  return route.redirect !== undefined;
251
284
  });
252
285
  const redirectPromises = routePairsWithRedirects.map(([route, event]) => {
253
- assertIsDefined(route.redirect);
286
+ (0, utils_1.assertIsDefined)(route.redirect);
254
287
  return route.redirect({
255
288
  signal: controller.signal,
256
289
  query: event.query,
@@ -284,11 +317,11 @@ export function buildRootComponent(machine, routing) {
284
317
  controller.abort();
285
318
  };
286
319
  }, [activeRoute]);
287
- useEffect(() => {
320
+ (0, react_2.useEffect)(() => {
288
321
  if (routing) {
289
322
  const { getPathName = () => routing.history.location.pathname, getQueryString = () => routing.history.location.search, } = routing;
290
323
  const queryString = getQueryString();
291
- const result = handleLocationChange(routing.routes, routing.basePath, getPathName(), getQueryString(), { onloadEvent: isLikelyPageLoad() });
324
+ const result = (0, routing_1.handleLocationChange)(routing.routes, routing.basePath, getPathName(), getQueryString(), { onloadEvent: (0, utils_1.isLikelyPageLoad)() });
292
325
  if (result) {
293
326
  setActiveRouteEvents(result.events);
294
327
  setActiveRoute({ ...result.matchedRoute });
@@ -299,11 +332,11 @@ export function buildRootComponent(machine, routing) {
299
332
  routing.history.replace(`${getPathName()}${queryString}`, {});
300
333
  }
301
334
  }, []);
302
- useEffect(() => {
335
+ (0, react_2.useEffect)(() => {
303
336
  if (routing) {
304
337
  const unsub = routing.history.listen((location) => {
305
338
  var _a;
306
- const result = handleLocationChange(routing.routes, routing.basePath, location.pathname, location.search, (_a = location.state) === null || _a === void 0 ? void 0 : _a.meta);
339
+ const result = (0, routing_1.handleLocationChange)(routing.routes, routing.basePath, location.pathname, location.search, (_a = location.state) === null || _a === void 0 ? void 0 : _a.meta);
307
340
  if (result) {
308
341
  setActiveRouteEvents(result.events);
309
342
  setActiveRoute({ ...result.matchedRoute });
@@ -315,26 +348,29 @@ export function buildRootComponent(machine, routing) {
315
348
  }
316
349
  return undefined;
317
350
  }, []);
318
- const routingProviderValue = useMemo(() => {
351
+ const routingProviderValue = (0, react_2.useMemo)(() => {
352
+ // Just to satisfy linter, need this memo to be re-calculated on route changes
353
+ activeRoute;
319
354
  if (!routing) {
320
355
  return null;
321
356
  }
322
357
  return {
323
358
  activeRouteEvents: activeRouteEventsRef,
324
359
  };
325
- }, []);
360
+ }, [activeRoute]);
326
361
  if (!interpreter.initialized) {
327
362
  setTimeout(() => forceRender(!forceRenderValue), 0);
328
363
  return null;
329
364
  }
330
365
  if (routingProviderValue) {
331
- return (React.createElement(RoutingContext.Provider, { value: routingProviderValue },
332
- React.createElement(XstateTreeView, { interpreter: interpreter })));
366
+ return (react_2.default.createElement(routing_1.RoutingContext.Provider, { value: routingProviderValue },
367
+ react_2.default.createElement(XstateTreeView, { interpreter: interpreter })));
333
368
  }
334
369
  else {
335
- return React.createElement(XstateTreeView, { interpreter: interpreter });
370
+ return react_2.default.createElement(XstateTreeView, { interpreter: interpreter });
336
371
  }
337
372
  };
338
373
  RootComponent.rootMachine = machine;
339
374
  return RootComponent;
340
375
  }
376
+ exports.buildRootComponent = buildRootComponent;
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": "4.2.0",
5
+ "version": "4.3.0-beta.2",
6
6
  "license": "MIT",
7
7
  "description": "Build UIs with Actors using xstate and React",
8
8
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "@testing-library/dom": "^8.14.0",
35
35
  "@testing-library/jest-dom": "^5.16.1",
36
36
  "@testing-library/react": "^13.4.0",
37
- "@testing-library/user-event": "^13.5.0",
37
+ "@testing-library/user-event": "^14.4.3",
38
38
  "@types/history": "^4.7.7",
39
39
  "@types/jest": "^28.1.4",
40
40
  "@types/react": "^17.0.29",