@koordinates/xstate-tree 4.2.0 → 4.3.0-beta.10
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/README.md +1 -1
- package/lib/builders.js +18 -7
- package/lib/index.js +40 -8
- package/lib/lazy.js +20 -13
- package/lib/routing/Link.js +63 -13
- package/lib/routing/createRoute/createRoute.js +24 -12
- package/lib/routing/createRoute/index.js +5 -1
- package/lib/routing/handleLocationChange/handleLocationChange.js +13 -8
- package/lib/routing/handleLocationChange/index.js +5 -1
- package/lib/routing/index.js +21 -8
- package/lib/routing/joinRoutes.js +5 -1
- package/lib/routing/matchRoute/index.js +5 -1
- package/lib/routing/matchRoute/matchRoute.js +5 -1
- package/lib/routing/providers.js +23 -7
- package/lib/routing/routingEvent.js +2 -1
- package/lib/routing/useHref.js +7 -3
- package/lib/routing/useIsRouteActive.js +7 -3
- package/lib/routing/useRouteArgsIfActive.js +11 -7
- package/lib/setupScript.js +3 -1
- package/lib/slots/index.js +17 -1
- package/lib/slots/slots.js +9 -4
- package/lib/testingUtilities.js +54 -25
- package/lib/types.js +2 -1
- package/lib/useConstant.js +7 -3
- package/lib/useService.js +16 -11
- package/lib/utils.js +40 -83
- package/lib/xstate-tree.d.ts +33 -2
- package/lib/xstateTree.js +117 -64
- package/package.json +5 -4
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRouteArgsIfActive = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const providers_1 = require("./providers");
|
|
6
|
+
const useIsRouteActive_1 = require("./useIsRouteActive");
|
|
4
7
|
/**
|
|
5
8
|
* @public
|
|
6
9
|
* Returns the arguments for the given route if the route is active.
|
|
@@ -10,17 +13,18 @@ import { useIsRouteActive } from "./useIsRouteActive";
|
|
|
10
13
|
* @returns the arguments for the given route if the route is active, undefined otherwise
|
|
11
14
|
* @throws if used outside of an xstate-tree root
|
|
12
15
|
*/
|
|
13
|
-
|
|
14
|
-
const isActive = useIsRouteActive(route);
|
|
15
|
-
const activeRoutes = useActiveRouteEvents();
|
|
16
|
+
function useRouteArgsIfActive(route) {
|
|
17
|
+
const isActive = (0, useIsRouteActive_1.useIsRouteActive)(route);
|
|
18
|
+
const activeRoutes = (0, providers_1.useActiveRouteEvents)();
|
|
16
19
|
if (!isActive) {
|
|
17
20
|
return undefined;
|
|
18
21
|
}
|
|
19
22
|
const activeRoute = activeRoutes === null || activeRoutes === void 0 ? void 0 : activeRoutes.find((activeRoute) => activeRoute.type === route.event);
|
|
20
|
-
assertIsDefined(activeRoute, "active route is not defined, but the route is active??");
|
|
23
|
+
(0, utils_1.assertIsDefined)(activeRoute, "active route is not defined, but the route is active??");
|
|
21
24
|
return {
|
|
22
25
|
params: activeRoute.params,
|
|
23
26
|
query: activeRoute.query,
|
|
24
27
|
meta: activeRoute.meta,
|
|
25
28
|
};
|
|
26
29
|
}
|
|
30
|
+
exports.useRouteArgsIfActive = useRouteArgsIfActive;
|
package/lib/setupScript.js
CHANGED
package/lib/slots/index.js
CHANGED
|
@@ -1 +1,17 @@
|
|
|
1
|
-
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./slots"), exports);
|
package/lib/slots/slots.js
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.multiSlot = exports.singleSlot = exports.SlotType = void 0;
|
|
1
4
|
/**
|
|
2
5
|
* @public
|
|
3
6
|
*/
|
|
4
|
-
|
|
7
|
+
var SlotType;
|
|
5
8
|
(function (SlotType) {
|
|
6
9
|
SlotType[SlotType["SingleSlot"] = 0] = "SingleSlot";
|
|
7
10
|
SlotType[SlotType["MultiSlot"] = 1] = "MultiSlot";
|
|
8
|
-
})(SlotType || (SlotType = {}));
|
|
11
|
+
})(SlotType = exports.SlotType || (exports.SlotType = {}));
|
|
9
12
|
/**
|
|
10
13
|
* @public
|
|
11
14
|
*/
|
|
12
|
-
|
|
15
|
+
function singleSlot(name) {
|
|
13
16
|
return {
|
|
14
17
|
type: SlotType.SingleSlot,
|
|
15
18
|
name,
|
|
16
19
|
getId: () => `${name.toLowerCase()}-slot`,
|
|
17
20
|
};
|
|
18
21
|
}
|
|
22
|
+
exports.singleSlot = singleSlot;
|
|
19
23
|
/**
|
|
20
24
|
* @public
|
|
21
25
|
*/
|
|
22
|
-
|
|
26
|
+
function multiSlot(name) {
|
|
23
27
|
return {
|
|
24
28
|
type: SlotType.MultiSlot,
|
|
25
29
|
name: `${name}Multi`,
|
|
26
30
|
getId: (id) => `${id}-${name.toLowerCase()}multi-slots`,
|
|
27
31
|
};
|
|
28
32
|
}
|
|
33
|
+
exports.multiSlot = multiSlot;
|
package/lib/testingUtilities.js
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.buildTestRootComponent = exports.buildViewProps = exports.genericSlotsTestingDummy = exports.slotTestingDummyFactory = void 0;
|
|
1
27
|
// ignore file coverage
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
28
|
+
const react_1 = require("@xstate/react");
|
|
29
|
+
const react_2 = __importStar(require("react"));
|
|
30
|
+
const tiny_emitter_1 = require("tiny-emitter");
|
|
31
|
+
const xstate_1 = require("xstate");
|
|
32
|
+
const builders_1 = require("./builders");
|
|
33
|
+
const utils_1 = require("./utils");
|
|
34
|
+
const xstateTree_1 = require("./xstateTree");
|
|
9
35
|
/**
|
|
10
36
|
* @public
|
|
11
37
|
*
|
|
@@ -14,8 +40,8 @@ import { emitter, recursivelySend, XstateTreeView } from "./xstateTree";
|
|
|
14
40
|
* @param name - the string to render in the machines view
|
|
15
41
|
* @returns a dummy machine that renders a div containing the supplied string
|
|
16
42
|
*/
|
|
17
|
-
|
|
18
|
-
return buildXStateTreeMachine(createMachine({
|
|
43
|
+
function slotTestingDummyFactory(name) {
|
|
44
|
+
return (0, builders_1.buildXStateTreeMachine)((0, xstate_1.createMachine)({
|
|
19
45
|
id: name,
|
|
20
46
|
initial: "idle",
|
|
21
47
|
states: {
|
|
@@ -25,20 +51,21 @@ export function slotTestingDummyFactory(name) {
|
|
|
25
51
|
actions: () => ({}),
|
|
26
52
|
selectors: () => ({}),
|
|
27
53
|
slots: [],
|
|
28
|
-
view: () => (
|
|
29
|
-
|
|
54
|
+
view: () => (react_2.default.createElement("div", null,
|
|
55
|
+
react_2.default.createElement("p", null, name))),
|
|
30
56
|
});
|
|
31
57
|
}
|
|
58
|
+
exports.slotTestingDummyFactory = slotTestingDummyFactory;
|
|
32
59
|
/**
|
|
33
60
|
* @public
|
|
34
61
|
*
|
|
35
62
|
* Can be used as the slots prop for an xstate-tree view, will render a div containing a <p>slotName-slot<p> for each slot
|
|
36
63
|
*/
|
|
37
|
-
|
|
64
|
+
exports.genericSlotsTestingDummy = new Proxy({}, {
|
|
38
65
|
get(_target, prop) {
|
|
39
|
-
return () => (
|
|
40
|
-
|
|
41
|
-
|
|
66
|
+
return () => (react_2.default.createElement("div", null,
|
|
67
|
+
react_2.default.createElement("p", null,
|
|
68
|
+
react_2.default.createElement(react_2.default.Fragment, null,
|
|
42
69
|
prop,
|
|
43
70
|
"-slot"))));
|
|
44
71
|
},
|
|
@@ -52,12 +79,13 @@ export const genericSlotsTestingDummy = new Proxy({}, {
|
|
|
52
79
|
* @param props - The actions/selectors props to pass to the view
|
|
53
80
|
* @returns An object with the view's selectors, actions, and inState function props
|
|
54
81
|
*/
|
|
55
|
-
|
|
82
|
+
function buildViewProps(_view, props) {
|
|
56
83
|
return {
|
|
57
84
|
...props,
|
|
58
85
|
inState: (testState) => (state) => state === testState || testState.startsWith(state),
|
|
59
86
|
};
|
|
60
87
|
}
|
|
88
|
+
exports.buildViewProps = buildViewProps;
|
|
61
89
|
/**
|
|
62
90
|
* @public
|
|
63
91
|
*
|
|
@@ -73,7 +101,7 @@ export function buildViewProps(_view, props) {
|
|
|
73
101
|
*
|
|
74
102
|
* It also delays for 5ms to ensure any React re-rendering happens in response to the state transition
|
|
75
103
|
*/
|
|
76
|
-
|
|
104
|
+
function buildTestRootComponent(machine, logger) {
|
|
77
105
|
if (!machine.meta) {
|
|
78
106
|
throw new Error("Root machine has no meta");
|
|
79
107
|
}
|
|
@@ -81,19 +109,19 @@ export function buildTestRootComponent(machine, logger) {
|
|
|
81
109
|
(machine.meta.builderVersion === 2 && !machine.meta.View)) {
|
|
82
110
|
throw new Error("Root machine has no associated view");
|
|
83
111
|
}
|
|
84
|
-
const onChangeEmitter = new TinyEmitter();
|
|
112
|
+
const onChangeEmitter = new tiny_emitter_1.TinyEmitter();
|
|
85
113
|
function addTransitionListener(listener) {
|
|
86
114
|
onChangeEmitter.once("transition", listener);
|
|
87
115
|
}
|
|
88
116
|
return {
|
|
89
117
|
rootComponent: function XstateTreeRootComponent() {
|
|
90
|
-
const [_, __, interpreter] = useMachine(machine, { devTools: true });
|
|
91
|
-
useEffect(() => {
|
|
118
|
+
const [_, __, interpreter] = (0, react_1.useMachine)(machine, { devTools: true });
|
|
119
|
+
(0, react_2.useEffect)(() => {
|
|
92
120
|
function handler(event) {
|
|
93
|
-
recursivelySend(interpreter, event);
|
|
121
|
+
(0, xstateTree_1.recursivelySend)(interpreter, event);
|
|
94
122
|
}
|
|
95
123
|
function changeHandler(ctx, oldCtx) {
|
|
96
|
-
logger("onChange: ",
|
|
124
|
+
logger("onChange: ", (0, utils_1.difference)(oldCtx, ctx));
|
|
97
125
|
onChangeEmitter.emit("changed", ctx);
|
|
98
126
|
}
|
|
99
127
|
function onEventHandler(e) {
|
|
@@ -106,9 +134,9 @@ export function buildTestRootComponent(machine, logger) {
|
|
|
106
134
|
interpreter.onChange(changeHandler);
|
|
107
135
|
interpreter.onEvent(onEventHandler);
|
|
108
136
|
interpreter.onTransition(onTransitionHandler);
|
|
109
|
-
emitter.on("event", handler);
|
|
137
|
+
xstateTree_1.emitter.on("event", handler);
|
|
110
138
|
return () => {
|
|
111
|
-
emitter.off("event", handler);
|
|
139
|
+
xstateTree_1.emitter.off("event", handler);
|
|
112
140
|
interpreter.off(changeHandler);
|
|
113
141
|
interpreter.off(onEventHandler);
|
|
114
142
|
interpreter.off(onTransitionHandler);
|
|
@@ -117,7 +145,7 @@ export function buildTestRootComponent(machine, logger) {
|
|
|
117
145
|
if (!interpreter.initialized) {
|
|
118
146
|
return null;
|
|
119
147
|
}
|
|
120
|
-
return
|
|
148
|
+
return react_2.default.createElement(xstateTree_1.XstateTreeView, { interpreter: interpreter });
|
|
121
149
|
},
|
|
122
150
|
addTransitionListener,
|
|
123
151
|
awaitTransition() {
|
|
@@ -129,3 +157,4 @@ export function buildTestRootComponent(machine, logger) {
|
|
|
129
157
|
},
|
|
130
158
|
};
|
|
131
159
|
}
|
|
160
|
+
exports.buildTestRootComponent = buildTestRootComponent;
|
package/lib/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/lib/useConstant.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useConstant = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useConstant(fn) {
|
|
6
|
+
const ref = (0, react_1.useRef)();
|
|
4
7
|
if (!ref.current) {
|
|
5
8
|
ref.current = { v: fn() };
|
|
6
9
|
}
|
|
7
10
|
return ref.current.v;
|
|
8
11
|
}
|
|
12
|
+
exports.useConstant = useConstant;
|
package/lib/useService.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useService = exports.loggingMetaOptions = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
3
6
|
/**
|
|
4
7
|
* @public
|
|
5
8
|
*/
|
|
6
|
-
|
|
9
|
+
function loggingMetaOptions(ignoredEvents, ignoreContext = undefined) {
|
|
7
10
|
const ignoredEventMap = new Map();
|
|
8
11
|
ignoredEvents.forEach((event) => {
|
|
9
12
|
ignoredEventMap.set(event, true);
|
|
@@ -15,17 +18,18 @@ export function loggingMetaOptions(ignoredEvents, ignoreContext = undefined) {
|
|
|
15
18
|
},
|
|
16
19
|
};
|
|
17
20
|
}
|
|
21
|
+
exports.loggingMetaOptions = loggingMetaOptions;
|
|
18
22
|
/**
|
|
19
23
|
* @internal
|
|
20
24
|
*/
|
|
21
|
-
|
|
22
|
-
const [current, setCurrent] = useState(service.state);
|
|
23
|
-
const [children, setChildren] = useState(service.children);
|
|
24
|
-
const childrenRef = useRef(new Map());
|
|
25
|
-
useEffect(() => {
|
|
25
|
+
function useService(service) {
|
|
26
|
+
const [current, setCurrent] = (0, react_1.useState)(service.state);
|
|
27
|
+
const [children, setChildren] = (0, react_1.useState)(service.children);
|
|
28
|
+
const childrenRef = (0, react_1.useRef)(new Map());
|
|
29
|
+
(0, react_1.useEffect)(() => {
|
|
26
30
|
childrenRef.current = children;
|
|
27
31
|
}, [children]);
|
|
28
|
-
useEffect(function () {
|
|
32
|
+
(0, react_1.useEffect)(function () {
|
|
29
33
|
// Set to current service state as there is a possibility
|
|
30
34
|
// of a transition occurring between the initial useState()
|
|
31
35
|
// initialization and useEffect() commit.
|
|
@@ -34,7 +38,7 @@ export function useService(service) {
|
|
|
34
38
|
const listener = function (state) {
|
|
35
39
|
if (state.changed) {
|
|
36
40
|
setCurrent(state);
|
|
37
|
-
if (!isEqual(childrenRef.current, service.children)) {
|
|
41
|
+
if (!(0, utils_1.isEqual)(childrenRef.current, service.children)) {
|
|
38
42
|
setChildren(new Map(service.children));
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -44,7 +48,7 @@ export function useService(service) {
|
|
|
44
48
|
sub.unsubscribe();
|
|
45
49
|
};
|
|
46
50
|
}, [service, setChildren]);
|
|
47
|
-
useEffect(() => {
|
|
51
|
+
(0, react_1.useEffect)(() => {
|
|
48
52
|
function handler(event) {
|
|
49
53
|
var _a, _b, _c;
|
|
50
54
|
if (event.type.includes("done")) {
|
|
@@ -81,3 +85,4 @@ export function useService(service) {
|
|
|
81
85
|
children,
|
|
82
86
|
];
|
|
83
87
|
}
|
|
88
|
+
exports.useService = useService;
|
package/lib/utils.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeMeta = exports.isNil = exports.isEqual = exports.difference = exports.isLikelyPageLoad = exports.assert = exports.assertIsDefined = exports.delay = void 0;
|
|
4
|
+
function delay(ms = 0) {
|
|
2
5
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
6
|
}
|
|
4
|
-
|
|
7
|
+
exports.delay = delay;
|
|
8
|
+
function assertIsDefined(val, msg) {
|
|
5
9
|
if (val === undefined || val === null) {
|
|
6
10
|
throw new Error(`Expected 'val' to be defined, but received ${val} ${msg ? `(${msg})` : ""}`);
|
|
7
11
|
}
|
|
8
12
|
}
|
|
9
|
-
|
|
13
|
+
exports.assertIsDefined = assertIsDefined;
|
|
14
|
+
function assert(value, msg) {
|
|
10
15
|
if (typeof expect !== "undefined") {
|
|
11
16
|
if (value !== true && msg) {
|
|
12
17
|
console.error(msg);
|
|
@@ -20,7 +25,8 @@ export function assert(value, msg) {
|
|
|
20
25
|
throw new Error("assertion failed");
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
|
-
|
|
28
|
+
exports.assert = assert;
|
|
29
|
+
function isLikelyPageLoad() {
|
|
24
30
|
// without performance API, we can't tell if this is a page load
|
|
25
31
|
if (typeof performance === "undefined") {
|
|
26
32
|
return false;
|
|
@@ -28,91 +34,31 @@ export function isLikelyPageLoad() {
|
|
|
28
34
|
// if it's been < 5 seconds since the page was loaded, it's probably a page load
|
|
29
35
|
return performance.now() < 5000;
|
|
30
36
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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;
|
|
37
|
+
exports.isLikelyPageLoad = isLikelyPageLoad;
|
|
38
|
+
function difference(a, b) {
|
|
39
|
+
const result = {};
|
|
40
|
+
for (const key in b) {
|
|
41
|
+
if (!a.hasOwnProperty(key)) {
|
|
42
|
+
result[key] = b[key];
|
|
58
43
|
}
|
|
59
|
-
|
|
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;
|
|
44
|
+
else if (Array.isArray(b[key]) && Array.isArray(a[key])) {
|
|
45
|
+
if (JSON.stringify(b[key]) !== JSON.stringify(a[key])) {
|
|
46
|
+
result[key] = b[key];
|
|
88
47
|
}
|
|
89
|
-
return;
|
|
90
48
|
}
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
|
|
49
|
+
else if (typeof b[key] === "object" && typeof a[key] === "object") {
|
|
50
|
+
const value = difference(a[key], b[key]);
|
|
51
|
+
if (Object.keys(value).length > 0) {
|
|
52
|
+
result[key] = value;
|
|
94
53
|
}
|
|
95
54
|
}
|
|
96
|
-
else {
|
|
97
|
-
|
|
98
|
-
diffs[key] = item2;
|
|
99
|
-
}
|
|
55
|
+
else if (b[key] !== a[key]) {
|
|
56
|
+
result[key] = b[key];
|
|
100
57
|
}
|
|
101
58
|
}
|
|
102
|
-
|
|
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;
|
|
59
|
+
return result;
|
|
115
60
|
}
|
|
61
|
+
exports.difference = difference;
|
|
116
62
|
/*
|
|
117
63
|
* @private
|
|
118
64
|
*
|
|
@@ -122,7 +68,7 @@ export function difference(obj1, obj2) {
|
|
|
122
68
|
* @param {*} obj2 The second item
|
|
123
69
|
* @return {Boolean} Returns true if they're equal in value
|
|
124
70
|
*/
|
|
125
|
-
|
|
71
|
+
function isEqual(obj1, obj2) {
|
|
126
72
|
/**
|
|
127
73
|
* More accurately check the type of a JavaScript object
|
|
128
74
|
* @param {Object} obj The object
|
|
@@ -168,8 +114,19 @@ export function isEqual(obj1, obj2) {
|
|
|
168
114
|
return areFunctionsEqual();
|
|
169
115
|
return arePrimitivesEqual();
|
|
170
116
|
}
|
|
171
|
-
|
|
117
|
+
exports.isEqual = isEqual;
|
|
118
|
+
function isNil(
|
|
172
119
|
// eslint-disable-next-line @rushstack/no-new-null
|
|
173
120
|
value) {
|
|
174
121
|
return value === null || value === undefined;
|
|
175
122
|
}
|
|
123
|
+
exports.isNil = isNil;
|
|
124
|
+
function mergeMeta(meta) {
|
|
125
|
+
return Object.keys(meta).reduce((acc, key) => {
|
|
126
|
+
const value = meta[key];
|
|
127
|
+
// Assuming each meta value is an object
|
|
128
|
+
Object.assign(acc, value);
|
|
129
|
+
return acc;
|
|
130
|
+
}, {});
|
|
131
|
+
}
|
|
132
|
+
exports.mergeMeta = mergeMeta;
|
package/lib/xstate-tree.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ export declare type AnyRoute = {
|
|
|
51
51
|
navigate: any;
|
|
52
52
|
getEvent: any;
|
|
53
53
|
event: string;
|
|
54
|
+
preload: any;
|
|
54
55
|
basePath: string;
|
|
55
56
|
history: () => XstateTreeHistory;
|
|
56
57
|
parent?: AnyRoute;
|
|
@@ -127,6 +128,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
127
128
|
querySchema?: TQuerySchema | undefined;
|
|
128
129
|
meta?: TMeta | undefined;
|
|
129
130
|
redirect?: RouteRedirect<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta> | undefined;
|
|
131
|
+
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>>> | undefined;
|
|
130
132
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, TEvent, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta>;
|
|
131
133
|
route<TBaseRoute_1 extends AnyRoute>(baseRoute?: TBaseRoute_1 | undefined): <TEvent_1 extends string, TParamsSchema_1 extends Z.ZodObject<any, "strip", Z.ZodTypeAny, {
|
|
132
134
|
[x: string]: any;
|
|
@@ -136,7 +138,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
136
138
|
[x: string]: any;
|
|
137
139
|
}, {
|
|
138
140
|
[x: string]: any;
|
|
139
|
-
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, }: {
|
|
141
|
+
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, }: {
|
|
140
142
|
event: TEvent_1;
|
|
141
143
|
paramsSchema?: TParamsSchema_1 | undefined;
|
|
142
144
|
querySchema?: TQuerySchema_1 | undefined;
|
|
@@ -157,6 +159,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
157
159
|
* Supplied with params/query objects and constructs the correct URL based on them
|
|
158
160
|
*/
|
|
159
161
|
reverser: RouteArgumentFunctions<string, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>>;
|
|
162
|
+
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>> | undefined;
|
|
160
163
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, TEvent_1, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1> & SharedMeta>;
|
|
161
164
|
};
|
|
162
165
|
|
|
@@ -352,7 +355,21 @@ export declare function lazy<TMachine extends AnyStateMachine>(factory: () => Pr
|
|
|
352
355
|
* The query/params/meta props are conditionally required based on the
|
|
353
356
|
* route passed as the To parameter
|
|
354
357
|
*/
|
|
355
|
-
export declare
|
|
358
|
+
export declare const Link: <TRoute extends AnyRoute>(props: {
|
|
359
|
+
to: TRoute;
|
|
360
|
+
children: React_2.ReactNode;
|
|
361
|
+
testId?: string | undefined;
|
|
362
|
+
/**
|
|
363
|
+
* onClick works as normal, but if you return false from it the navigation will not happen
|
|
364
|
+
*/
|
|
365
|
+
onClick?: ((e: React_2.MouseEvent<HTMLAnchorElement>) => boolean | void) | undefined;
|
|
366
|
+
preloadOnInteraction?: boolean | undefined;
|
|
367
|
+
preloadOnHoverMs?: number | undefined;
|
|
368
|
+
} & RouteArguments<TRoute extends Route<infer TParams, any, any, any> ? TParams : undefined, TRoute extends Route<any, infer TQuery, any, any> ? TQuery : undefined, TRoute extends Route<any, any, any, infer TMeta> ? TMeta : undefined> & Omit<React_2.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "onClick"> & {
|
|
369
|
+
ref?: React_2.ForwardedRef<HTMLAnchorElement> | undefined;
|
|
370
|
+
}) => ReturnType<typeof LinkInner>;
|
|
371
|
+
|
|
372
|
+
declare function LinkInner<TRoute extends AnyRoute>({ to, children, testId, preloadOnHoverMs, preloadOnInteraction, onMouseDown: _onMouseDown, onMouseEnter: _onMouseEnter, onMouseLeave: _onMouseLeave, ...rest }: LinkProps<TRoute>, ref: React_2.ForwardedRef<HTMLAnchorElement>): JSX.Element;
|
|
356
373
|
|
|
357
374
|
/**
|
|
358
375
|
* @public
|
|
@@ -365,6 +382,8 @@ export declare type LinkProps<TRoute extends AnyRoute, TRouteParams = TRoute ext
|
|
|
365
382
|
* onClick works as normal, but if you return false from it the navigation will not happen
|
|
366
383
|
*/
|
|
367
384
|
onClick?: (e: React_2.MouseEvent<HTMLAnchorElement>) => boolean | void;
|
|
385
|
+
preloadOnInteraction?: boolean;
|
|
386
|
+
preloadOnHoverMs?: number;
|
|
368
387
|
} & RouteArguments<TRouteParams, TRouteQuery, TRouteMeta> & Omit<React_2.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "onClick">;
|
|
369
388
|
|
|
370
389
|
/**
|
|
@@ -524,6 +543,17 @@ export declare type Route<TParams, TQuery, TEvent, TMeta> = {
|
|
|
524
543
|
* url via History.push
|
|
525
544
|
*/
|
|
526
545
|
navigate: RouteArgumentFunctions<void, TParams, TQuery, TMeta>;
|
|
546
|
+
/**
|
|
547
|
+
* Preloads data required by the route. Passed in query/params/meta objects as required by the route
|
|
548
|
+
*
|
|
549
|
+
* Must be idempotent as it may be called multiple times
|
|
550
|
+
*
|
|
551
|
+
* Can be called on
|
|
552
|
+
* * Mouse down on a Link
|
|
553
|
+
* * Hovering on a Link
|
|
554
|
+
* * When a route is matched
|
|
555
|
+
*/
|
|
556
|
+
preload: RouteArgumentFunctions<void, TParams, TQuery, TMeta>;
|
|
527
557
|
/**
|
|
528
558
|
* Returns an event object for this route based on the supplied params/query/meta
|
|
529
559
|
*
|
|
@@ -628,6 +658,7 @@ export declare type Selectors<TMachine extends AnyStateMachine, TOut> = (args: {
|
|
|
628
658
|
ctx: ContextFrom<TMachine>;
|
|
629
659
|
canHandleEvent: CanHandleEvent<TMachine>;
|
|
630
660
|
inState: MatchesFrom<TMachine>;
|
|
661
|
+
meta?: unknown;
|
|
631
662
|
}) => TOut;
|
|
632
663
|
|
|
633
664
|
/**
|