@koordinates/xstate-tree 2.0.4 → 2.0.5
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/routing/createRoute/createRoute.js +1 -1
- package/lib/testingUtilities.js +1 -23
- package/lib/useService.js +2 -6
- package/lib/utils.js +145 -0
- package/lib/xstateTree.js +1 -2
- package/package.json +55 -38
package/lib/testingUtilities.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// ignore file coverage
|
|
2
2
|
import { useMachine } from "@xstate/react";
|
|
3
|
-
import { transform, isEqual, isObject, isNil } from "lodash";
|
|
4
3
|
import React, { useEffect } from "react";
|
|
5
4
|
import { TinyEmitter } from "tiny-emitter";
|
|
6
5
|
import { createMachine, } from "xstate";
|
|
7
6
|
import { buildXStateTreeMachine } from "./builders";
|
|
7
|
+
import { difference } from "./utils";
|
|
8
8
|
import { emitter, recursivelySend, XstateTreeView } from "./xstateTree";
|
|
9
9
|
/**
|
|
10
10
|
* @public
|
|
@@ -115,25 +115,3 @@ export function buildTestRootComponent(machine, logger) {
|
|
|
115
115
|
},
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Deep diff between two object, using lodash
|
|
120
|
-
* @param {Object} object Object compared
|
|
121
|
-
* @param {Object} base Object to compare with
|
|
122
|
-
* @return {Object} Return a new object who represent the diff
|
|
123
|
-
*/
|
|
124
|
-
function difference(object, base) {
|
|
125
|
-
function changes(object, base) {
|
|
126
|
-
return transform(object, function (result, value, key) {
|
|
127
|
-
if (!isEqual(value, base[key])) {
|
|
128
|
-
result[key] =
|
|
129
|
-
isObject(value) && isObject(base[key])
|
|
130
|
-
? changes(value, base[key])
|
|
131
|
-
: value;
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
if (isNil(base)) {
|
|
136
|
-
return object;
|
|
137
|
-
}
|
|
138
|
-
return changes(object, base);
|
|
139
|
-
}
|
package/lib/useService.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { omit, isEqual } from "lodash";
|
|
2
1
|
import { useState, useRef, useEffect } from "react";
|
|
2
|
+
import { isEqual } from "./utils";
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
5
5
|
*/
|
|
@@ -60,11 +60,7 @@ export function useService(service) {
|
|
|
60
60
|
function transitionHandler(state) {
|
|
61
61
|
var _a, _b;
|
|
62
62
|
const ignoreContext = (_b = (_a = service.machine.meta) === null || _a === void 0 ? void 0 : _a.xstateTree) === null || _b === void 0 ? void 0 : _b.ignoreContext;
|
|
63
|
-
const context = ignoreContext
|
|
64
|
-
? ignoreContext.length > 0
|
|
65
|
-
? omit(state.context, ignoreContext)
|
|
66
|
-
: "[context omitted]"
|
|
67
|
-
: state.context;
|
|
63
|
+
const context = ignoreContext ? "[context omitted]" : state.context;
|
|
68
64
|
if (prevState) {
|
|
69
65
|
console.debug(`[xstate-tree] ${service.id} transitioning from`, prevState.value, "to", state.value, context);
|
|
70
66
|
}
|
package/lib/utils.js
CHANGED
|
@@ -28,3 +28,148 @@ export function isLikelyPageLoad() {
|
|
|
28
28
|
// if it's been < 5 seconds since the page was loaded, it's probably a page load
|
|
29
29
|
return performance.now() < 5000;
|
|
30
30
|
}
|
|
31
|
+
/*
|
|
32
|
+
* @private
|
|
33
|
+
*
|
|
34
|
+
* Find the differences between two objects and push to a new object
|
|
35
|
+
* (c) 2019 Chris Ferdinandi & Jascha Brinkmann, MIT License, https://gomakethings.com & https://twitter.com/jaschaio
|
|
36
|
+
* @param {Object} obj1 The original object
|
|
37
|
+
* @param {Object} obj2 The object to compare against it
|
|
38
|
+
* @return {Object} An object of differences between the two
|
|
39
|
+
*/
|
|
40
|
+
export function difference(obj1, obj2) {
|
|
41
|
+
if (!obj2 || Object.prototype.toString.call(obj2) !== "[object Object]") {
|
|
42
|
+
return obj1;
|
|
43
|
+
}
|
|
44
|
+
const diffs = {};
|
|
45
|
+
let key;
|
|
46
|
+
/**
|
|
47
|
+
* Check if two arrays are equal
|
|
48
|
+
* @param {Array} arr1 The first array
|
|
49
|
+
* @param {Array} arr2 The second array
|
|
50
|
+
* @return {Boolean} If true, both arrays are equal
|
|
51
|
+
*/
|
|
52
|
+
const arraysMatch = function arraysMatch(arr1, arr2) {
|
|
53
|
+
if (arr1.length !== arr2.length)
|
|
54
|
+
return false;
|
|
55
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
56
|
+
if (arr1[i] !== arr2[i])
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Compare two items and push non-matches to object
|
|
63
|
+
* @param {*} item1 The first item
|
|
64
|
+
* @param {*} item2 The second item
|
|
65
|
+
* @param {String} key The key in our object
|
|
66
|
+
*/
|
|
67
|
+
function compare(item1, item2, key) {
|
|
68
|
+
const type1 = Object.prototype.toString.call(item1);
|
|
69
|
+
const type2 = Object.prototype.toString.call(item2);
|
|
70
|
+
if (type2 === "[object Undefined]") {
|
|
71
|
+
diffs[key] = null;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (type1 !== type2) {
|
|
75
|
+
diffs[key] = item2;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (type1 === "[object Object]") {
|
|
79
|
+
const objDiff = difference(item1, item2);
|
|
80
|
+
if (Object.keys(objDiff).length > 0) {
|
|
81
|
+
diffs[key] = objDiff;
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (type1 === "[object Array]") {
|
|
86
|
+
if (!arraysMatch(item1, item2)) {
|
|
87
|
+
diffs[key] = item2;
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (type1 === "[object Function]") {
|
|
92
|
+
if (item1.toString() !== item2.toString()) {
|
|
93
|
+
diffs[key] = item2;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
if (item1 !== item2) {
|
|
98
|
+
diffs[key] = item2;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (key in obj1) {
|
|
103
|
+
if (obj1.hasOwnProperty(key)) {
|
|
104
|
+
compare(obj1[key], obj2[key], key);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (key in obj2) {
|
|
108
|
+
if (obj2.hasOwnProperty(key)) {
|
|
109
|
+
if (!obj1[key] && obj1[key] !== obj2[key]) {
|
|
110
|
+
diffs[key] = obj2[key];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return diffs;
|
|
115
|
+
}
|
|
116
|
+
/*
|
|
117
|
+
* @private
|
|
118
|
+
*
|
|
119
|
+
* Check if two objects or arrays are equal
|
|
120
|
+
* (c) 2021 Chris Ferdinandi, MIT License, https://gomakethings.com
|
|
121
|
+
* @param {*} obj1 The first item
|
|
122
|
+
* @param {*} obj2 The second item
|
|
123
|
+
* @return {Boolean} Returns true if they're equal in value
|
|
124
|
+
*/
|
|
125
|
+
export function isEqual(obj1, obj2) {
|
|
126
|
+
/**
|
|
127
|
+
* More accurately check the type of a JavaScript object
|
|
128
|
+
* @param {Object} obj The object
|
|
129
|
+
* @return {String} The object type
|
|
130
|
+
*/
|
|
131
|
+
function getType(obj) {
|
|
132
|
+
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
function areArraysEqual() {
|
|
135
|
+
if (obj1.length !== obj2.length)
|
|
136
|
+
return false;
|
|
137
|
+
for (let i = 0; i < obj1.length; i++) {
|
|
138
|
+
if (!isEqual(obj1[i], obj2[i]))
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
function areObjectsEqual() {
|
|
144
|
+
if (Object.keys(obj1).length !== Object.keys(obj2).length)
|
|
145
|
+
return false;
|
|
146
|
+
for (const key in obj1) {
|
|
147
|
+
if (Object.prototype.hasOwnProperty.call(obj1, key)) {
|
|
148
|
+
if (!isEqual(obj1[key], obj2[key]))
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
function areFunctionsEqual() {
|
|
155
|
+
return obj1.toString() === obj2.toString();
|
|
156
|
+
}
|
|
157
|
+
function arePrimitivesEqual() {
|
|
158
|
+
return obj1 === obj2;
|
|
159
|
+
}
|
|
160
|
+
const type = getType(obj1);
|
|
161
|
+
if (type !== getType(obj2))
|
|
162
|
+
return false;
|
|
163
|
+
if (type === "array")
|
|
164
|
+
return areArraysEqual();
|
|
165
|
+
if (type === "object")
|
|
166
|
+
return areObjectsEqual();
|
|
167
|
+
if (type === "function")
|
|
168
|
+
return areFunctionsEqual();
|
|
169
|
+
return arePrimitivesEqual();
|
|
170
|
+
}
|
|
171
|
+
export function isNil(
|
|
172
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
173
|
+
value) {
|
|
174
|
+
return value === null || value === undefined;
|
|
175
|
+
}
|
package/lib/xstateTree.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useMachine } from "@xstate/react";
|
|
2
2
|
import memoize from "fast-memoize";
|
|
3
|
-
import { reduce } from "lodash";
|
|
4
3
|
import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
5
4
|
import { TinyEmitter } from "tiny-emitter";
|
|
6
5
|
import { handleLocationChange, RoutingContext, } from "./routing";
|
|
@@ -64,7 +63,7 @@ const getMultiSlotViewForChildren = memoize((parent, slot) => {
|
|
|
64
63
|
});
|
|
65
64
|
function useSlots(interpreter, slots) {
|
|
66
65
|
return useConstant(() => {
|
|
67
|
-
return reduce(
|
|
66
|
+
return slots.reduce((views, slot) => {
|
|
68
67
|
return {
|
|
69
68
|
...views,
|
|
70
69
|
[slot]: () => {
|
package/package.json
CHANGED
|
@@ -2,53 +2,70 @@
|
|
|
2
2
|
"name": "@koordinates/xstate-tree",
|
|
3
3
|
"main": "lib/index.js",
|
|
4
4
|
"types": "lib/xstate-tree.d.ts",
|
|
5
|
-
"version": "2.0.
|
|
5
|
+
"version": "2.0.5",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"description": "Build UIs with Actors using xstate and React",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"react",
|
|
10
|
+
"javascript",
|
|
11
|
+
"typescript",
|
|
12
|
+
"ui",
|
|
13
|
+
"actors",
|
|
14
|
+
"state-machine",
|
|
15
|
+
"actor-model",
|
|
16
|
+
"xstate"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/koordinates/xstate-tree/",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/koordinates/xstate-tree/issues/"
|
|
21
|
+
},
|
|
6
22
|
"dependencies": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"path-to-regexp": "6.2.0",
|
|
12
|
-
"query-string": "6.12.1",
|
|
13
|
-
"react": "18.1.0",
|
|
14
|
-
"react-dom": "18.1.0",
|
|
15
|
-
"rxjs": "6.6.2",
|
|
16
|
-
"tiny-emitter": "2.1.0",
|
|
17
|
-
"typescript": "4.7.3"
|
|
23
|
+
"fast-memoize": "^2.5.2",
|
|
24
|
+
"path-to-regexp": "^6.2.0",
|
|
25
|
+
"query-string": "^6.12.1",
|
|
26
|
+
"tiny-emitter": "^2.1.0"
|
|
18
27
|
},
|
|
19
28
|
"devDependencies": {
|
|
20
|
-
"@
|
|
21
|
-
"@
|
|
29
|
+
"@commitlint/cli": "^17.1.2",
|
|
30
|
+
"@commitlint/config-conventional": "^17.1.0",
|
|
31
|
+
"@microsoft/api-extractor": "^7.28.4",
|
|
32
|
+
"@rushstack/eslint-config": "^2.6.0",
|
|
22
33
|
"@saithodev/semantic-release-backmerge": "^2.1.2",
|
|
23
|
-
"@testing-library/dom": "8.14.0",
|
|
24
|
-
"@testing-library/jest-dom": "5.16.1",
|
|
25
|
-
"@testing-library/react": "10.4.8",
|
|
26
|
-
"@testing-library/user-event": "13.5.0",
|
|
27
|
-
"@types/history": "4.7.7",
|
|
28
|
-
"@types/jest": "28.1.4",
|
|
29
|
-
"@types/
|
|
30
|
-
"@types/react": "
|
|
31
|
-
"@types/
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"classnames": "2.3.1",
|
|
34
|
+
"@testing-library/dom": "^8.14.0",
|
|
35
|
+
"@testing-library/jest-dom": "^5.16.1",
|
|
36
|
+
"@testing-library/react": "^10.4.8",
|
|
37
|
+
"@testing-library/user-event": "^13.5.0",
|
|
38
|
+
"@types/history": "^4.7.7",
|
|
39
|
+
"@types/jest": "^28.1.4",
|
|
40
|
+
"@types/react": "^17.0.29",
|
|
41
|
+
"@types/react-dom": "^18.0.6",
|
|
42
|
+
"@types/testing-library__jest-dom": "^5.14.1",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^5.30.5",
|
|
44
|
+
"@xstate/react": "^3.0.0",
|
|
45
|
+
"classnames": "^2.3.1",
|
|
35
46
|
"cz-conventional-changelog": "^3.3.0",
|
|
36
|
-
"eslint": "7.32.0",
|
|
37
|
-
"eslint-import-resolver-typescript": "2.7.1",
|
|
38
|
-
"eslint-plugin-import": "2.26.0",
|
|
39
|
-
"eslint-plugin-prettier": "4.2.1",
|
|
40
|
-
"eslint-plugin-react-hooks": "4.3.0",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
47
|
+
"eslint": "^7.32.0",
|
|
48
|
+
"eslint-import-resolver-typescript": "^2.7.1",
|
|
49
|
+
"eslint-plugin-import": "^2.26.0",
|
|
50
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
51
|
+
"eslint-plugin-react-hooks": "^4.3.0",
|
|
52
|
+
"history": "^4.10.1",
|
|
53
|
+
"husky": "^8.0.1",
|
|
54
|
+
"jest": "^28.0.3",
|
|
55
|
+
"jest-environment-jsdom": "^28.0.1",
|
|
56
|
+
"react": "^18.1.0",
|
|
57
|
+
"react-dom": "^18.1.0",
|
|
58
|
+
"rimraf": "^3.0.2",
|
|
59
|
+
"semantic-release": "^19.0.3",
|
|
45
60
|
"semantic-release-npm-github-publish": "^1.5.1",
|
|
46
|
-
"ts-jest": "28.0.5",
|
|
47
|
-
"
|
|
61
|
+
"ts-jest": "^28.0.5",
|
|
62
|
+
"typescript": "^4.7.3",
|
|
63
|
+
"xstate": "^4.32.0"
|
|
48
64
|
},
|
|
49
65
|
"peerDependencies": {
|
|
66
|
+
"@xstate/react": "^3.x",
|
|
50
67
|
"xstate": ">= 4.20 < 5.0.0",
|
|
51
|
-
"zod": "3.x"
|
|
68
|
+
"zod": "^3.x"
|
|
52
69
|
},
|
|
53
70
|
"scripts": {
|
|
54
71
|
"lint": "eslint 'src/**/*'",
|