@xstate/react 4.0.0-beta.4 → 4.0.0-beta.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/dist/declarations/src/index.d.ts +6 -6
- package/dist/{useConstant-720f1662.cjs.prod.js → useConstant-2ee82f84.cjs.js} +1 -1
- package/dist/useConstant-ae6dceac.development.cjs.js +35 -0
- package/dist/useConstant-bac83df4.development.esm.js +13 -0
- package/dist/useConstant-c7ec0fdd.esm.js +13 -0
- package/dist/xstate-react.cjs.js +178 -4
- package/dist/{xstate-react.cjs.prod.js → xstate-react.development.cjs.js} +55 -65
- package/dist/xstate-react.development.esm.js +159 -0
- package/dist/xstate-react.esm.js +47 -79
- package/fsm/dist/xstate-react-fsm.cjs.js +65 -4
- package/fsm/dist/xstate-react-fsm.development.cjs.js +74 -0
- package/fsm/dist/xstate-react-fsm.development.esm.js +65 -0
- package/fsm/dist/xstate-react-fsm.esm.js +30 -42
- package/package.json +27 -3
- package/dist/declarations/src/useConstant.d.ts +0 -1
- package/dist/useConstant-23e96eea.cjs.dev.js +0 -91
- package/dist/useConstant-9bbaf12a.esm.js +0 -68
- package/dist/xstate-react.cjs.dev.js +0 -213
- package/fsm/dist/xstate-react-fsm.cjs.dev.js +0 -80
- package/fsm/dist/xstate-react-fsm.cjs.prod.js +0 -127
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { useActor } from
|
|
2
|
-
export { useActorRef } from
|
|
3
|
-
export { useSelector } from
|
|
4
|
-
export { shallowEqual } from
|
|
5
|
-
export { createActorContext } from
|
|
6
|
-
export { useMachine } from
|
|
1
|
+
export { useActor } from "./useActor.js";
|
|
2
|
+
export { useActorRef } from "./useActorRef.js";
|
|
3
|
+
export { useSelector } from "./useSelector.js";
|
|
4
|
+
export { shallowEqual } from "./shallowEqual.js";
|
|
5
|
+
export { createActorContext } from "./createActorContext.js";
|
|
6
|
+
export { useMachine } from "./useMachine.js";
|
|
@@ -23,7 +23,7 @@ function _interopNamespace(e) {
|
|
|
23
23
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
24
24
|
|
|
25
25
|
function useConstant(fn) {
|
|
26
|
-
|
|
26
|
+
const ref = React__namespace.useRef();
|
|
27
27
|
if (!ref.current) {
|
|
28
28
|
ref.current = {
|
|
29
29
|
v: fn()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
|
|
5
|
+
function _interopNamespace(e) {
|
|
6
|
+
if (e && e.__esModule) return e;
|
|
7
|
+
var n = Object.create(null);
|
|
8
|
+
if (e) {
|
|
9
|
+
Object.keys(e).forEach(function (k) {
|
|
10
|
+
if (k !== 'default') {
|
|
11
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return e[k]; }
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
n["default"] = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
24
|
+
|
|
25
|
+
function useConstant(fn) {
|
|
26
|
+
const ref = React__namespace.useRef();
|
|
27
|
+
if (!ref.current) {
|
|
28
|
+
ref.current = {
|
|
29
|
+
v: fn()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return ref.current.v;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.useConstant = useConstant;
|
package/dist/xstate-react.cjs.js
CHANGED
|
@@ -1,7 +1,181 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var withSelector = require('use-sync-external-store/shim/with-selector');
|
|
7
|
+
var xstate = require('xstate');
|
|
8
|
+
var useConstant = require('./useConstant-2ee82f84.cjs.js');
|
|
9
|
+
var useIsomorphicLayoutEffect = require('use-isomorphic-layout-effect');
|
|
10
|
+
require('xstate/actors');
|
|
11
|
+
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
13
|
+
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n["default"] = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
33
|
+
var useIsomorphicLayoutEffect__default = /*#__PURE__*/_interopDefault(useIsomorphicLayoutEffect);
|
|
34
|
+
|
|
35
|
+
function useIdleInterpreter(machine, options) {
|
|
36
|
+
const actorRef = useConstant.useConstant(() => {
|
|
37
|
+
return xstate.interpret(machine, options);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
41
|
+
useIsomorphicLayoutEffect__default["default"](() => {
|
|
42
|
+
actorRef.behavior.options = machine.options;
|
|
43
|
+
});
|
|
44
|
+
return actorRef;
|
|
45
|
+
}
|
|
46
|
+
function useActorRef(machine, ...[options = {}, observerOrListener]) {
|
|
47
|
+
const service = useIdleInterpreter(machine, options);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
if (!observerOrListener) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let sub = service.subscribe(xstate.toObserver(observerOrListener));
|
|
53
|
+
return () => {
|
|
54
|
+
sub.unsubscribe();
|
|
55
|
+
};
|
|
56
|
+
}, [observerOrListener]);
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
service.start();
|
|
59
|
+
return () => {
|
|
60
|
+
service.stop();
|
|
61
|
+
service.status = xstate.InterpreterStatus.NotStarted;
|
|
62
|
+
service._initState();
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
return service;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function identity(a) {
|
|
69
|
+
return a;
|
|
70
|
+
}
|
|
71
|
+
const isEqual = (prevState, nextState) => {
|
|
72
|
+
return prevState === nextState || nextState.changed === false;
|
|
73
|
+
};
|
|
74
|
+
function useActor(behavior, options = {}) {
|
|
75
|
+
const actorRef = useIdleInterpreter(behavior, options);
|
|
76
|
+
const getSnapshot = React.useCallback(() => {
|
|
77
|
+
return actorRef.getSnapshot();
|
|
78
|
+
}, [actorRef]);
|
|
79
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
80
|
+
const {
|
|
81
|
+
unsubscribe
|
|
82
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
83
|
+
return unsubscribe;
|
|
84
|
+
}, [actorRef]);
|
|
85
|
+
const actorSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
86
|
+
React.useEffect(() => {
|
|
87
|
+
actorRef.start();
|
|
88
|
+
return () => {
|
|
89
|
+
actorRef.stop();
|
|
90
|
+
actorRef.status = xstate.InterpreterStatus.NotStarted;
|
|
91
|
+
actorRef._initState();
|
|
92
|
+
};
|
|
93
|
+
}, [actorRef]);
|
|
94
|
+
return [actorSnapshot, actorRef.send, actorRef];
|
|
7
95
|
}
|
|
96
|
+
|
|
97
|
+
function defaultCompare(a, b) {
|
|
98
|
+
return a === b;
|
|
99
|
+
}
|
|
100
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
101
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
102
|
+
const {
|
|
103
|
+
unsubscribe
|
|
104
|
+
} = actor.subscribe(handleStoreChange);
|
|
105
|
+
return unsubscribe;
|
|
106
|
+
}, [actor]);
|
|
107
|
+
const boundGetSnapshot = React.useCallback(() => actor.getSnapshot(), [actor]);
|
|
108
|
+
const selectedSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
109
|
+
return selectedSnapshot;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
113
|
+
function is(x, y) {
|
|
114
|
+
if (x === y) {
|
|
115
|
+
return x !== 0 || y !== 0 || 1 / x === 1 / y;
|
|
116
|
+
} else {
|
|
117
|
+
return x !== x && y !== y;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function shallowEqual(objA, objB) {
|
|
121
|
+
if (is(objA, objB)) return true;
|
|
122
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const keysA = Object.keys(objA);
|
|
126
|
+
const keysB = Object.keys(objB);
|
|
127
|
+
if (keysA.length !== keysB.length) return false;
|
|
128
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
129
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
137
|
+
const ReactContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
138
|
+
const OriginalProvider = ReactContext.Provider;
|
|
139
|
+
function Provider({
|
|
140
|
+
children,
|
|
141
|
+
machine: providedMachine = machine
|
|
142
|
+
}) {
|
|
143
|
+
const actor = useActorRef(providedMachine, interpreterOptions, observerOrListener);
|
|
144
|
+
return /*#__PURE__*/React__namespace.createElement(OriginalProvider, {
|
|
145
|
+
value: actor,
|
|
146
|
+
children
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
Provider.displayName = `ActorProvider(${machine.id})`;
|
|
150
|
+
function useContext() {
|
|
151
|
+
const actor = React__namespace.useContext(ReactContext);
|
|
152
|
+
if (!actor) {
|
|
153
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
154
|
+
}
|
|
155
|
+
return actor;
|
|
156
|
+
}
|
|
157
|
+
function useSelector$1(selector, compare) {
|
|
158
|
+
const actor = useContext();
|
|
159
|
+
return useSelector(actor, selector, compare);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
Provider: Provider,
|
|
163
|
+
useActorRef: useContext,
|
|
164
|
+
useSelector: useSelector$1
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
*
|
|
170
|
+
* @deprecated Use `useActor(...)` instead.
|
|
171
|
+
*/
|
|
172
|
+
function useMachine(machine, options = {}) {
|
|
173
|
+
return useActor(machine, options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
exports.createActorContext = createActorContext;
|
|
177
|
+
exports.shallowEqual = shallowEqual;
|
|
178
|
+
exports.useActor = useActor;
|
|
179
|
+
exports.useActorRef = useActorRef;
|
|
180
|
+
exports.useMachine = useMachine;
|
|
181
|
+
exports.useSelector = useSelector;
|
|
@@ -5,9 +5,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var withSelector = require('use-sync-external-store/shim/with-selector');
|
|
7
7
|
var xstate = require('xstate');
|
|
8
|
-
var useConstant = require('./useConstant-
|
|
8
|
+
var useConstant = require('./useConstant-ae6dceac.development.cjs.js');
|
|
9
9
|
var useIsomorphicLayoutEffect = require('use-isomorphic-layout-effect');
|
|
10
|
-
require('xstate/actors');
|
|
10
|
+
var actors = require('xstate/actors');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
13
13
|
|
|
@@ -33,36 +33,36 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
|
33
33
|
var useIsomorphicLayoutEffect__default = /*#__PURE__*/_interopDefault(useIsomorphicLayoutEffect);
|
|
34
34
|
|
|
35
35
|
function useIdleInterpreter(machine, options) {
|
|
36
|
-
|
|
36
|
+
{
|
|
37
|
+
const [initialMachine] = React.useState(machine);
|
|
38
|
+
if (machine.config !== initialMachine.config) {
|
|
39
|
+
console.warn(`Actor logic has changed between renders. This is not supported and may lead to invalid snapshots.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const actorRef = useConstant.useConstant(() => {
|
|
37
43
|
return xstate.interpret(machine, options);
|
|
38
44
|
});
|
|
39
45
|
|
|
40
46
|
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
41
|
-
useIsomorphicLayoutEffect__default["default"](
|
|
47
|
+
useIsomorphicLayoutEffect__default["default"](() => {
|
|
42
48
|
actorRef.behavior.options = machine.options;
|
|
43
49
|
});
|
|
44
50
|
return actorRef;
|
|
45
51
|
}
|
|
46
|
-
function useActorRef(machine) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
var _ref$ = _ref[0],
|
|
51
|
-
options = _ref$ === void 0 ? {} : _ref$,
|
|
52
|
-
observerOrListener = _ref[1];
|
|
53
|
-
var service = useIdleInterpreter(machine, options);
|
|
54
|
-
React.useEffect(function () {
|
|
52
|
+
function useActorRef(machine, ...[options = {}, observerOrListener]) {
|
|
53
|
+
const service = useIdleInterpreter(machine, options);
|
|
54
|
+
React.useEffect(() => {
|
|
55
55
|
if (!observerOrListener) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
return
|
|
58
|
+
let sub = service.subscribe(xstate.toObserver(observerOrListener));
|
|
59
|
+
return () => {
|
|
60
60
|
sub.unsubscribe();
|
|
61
61
|
};
|
|
62
62
|
}, [observerOrListener]);
|
|
63
|
-
React.useEffect(
|
|
63
|
+
React.useEffect(() => {
|
|
64
64
|
service.start();
|
|
65
|
-
return
|
|
65
|
+
return () => {
|
|
66
66
|
service.stop();
|
|
67
67
|
service.status = xstate.InterpreterStatus.NotStarted;
|
|
68
68
|
service._initState();
|
|
@@ -74,24 +74,27 @@ function useActorRef(machine) {
|
|
|
74
74
|
function identity(a) {
|
|
75
75
|
return a;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
const isEqual = (prevState, nextState) => {
|
|
78
78
|
return prevState === nextState || nextState.changed === false;
|
|
79
79
|
};
|
|
80
|
-
function useActor(behavior) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
function useActor(behavior, options = {}) {
|
|
81
|
+
if (actors.isActorRef(behavior)) {
|
|
82
|
+
throw new Error(`useActor() expects actor logic (e.g. a machine), but received an ActorRef. Use the useSelector(actorRef, ...) hook instead to read the ActorRef's snapshot.`);
|
|
83
|
+
}
|
|
84
|
+
const actorRef = useIdleInterpreter(behavior, options);
|
|
85
|
+
const getSnapshot = React.useCallback(() => {
|
|
84
86
|
return actorRef.getSnapshot();
|
|
85
87
|
}, [actorRef]);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
unsubscribe
|
|
88
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
89
|
+
const {
|
|
90
|
+
unsubscribe
|
|
91
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
89
92
|
return unsubscribe;
|
|
90
93
|
}, [actorRef]);
|
|
91
|
-
|
|
92
|
-
React.useEffect(
|
|
94
|
+
const actorSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
95
|
+
React.useEffect(() => {
|
|
93
96
|
actorRef.start();
|
|
94
|
-
return
|
|
97
|
+
return () => {
|
|
95
98
|
actorRef.stop();
|
|
96
99
|
actorRef.status = xstate.InterpreterStatus.NotStarted;
|
|
97
100
|
actorRef._initState();
|
|
@@ -103,30 +106,18 @@ function useActor(behavior) {
|
|
|
103
106
|
function defaultCompare(a, b) {
|
|
104
107
|
return a === b;
|
|
105
108
|
}
|
|
106
|
-
function useSelector(actor, selector) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
110
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
111
|
+
const {
|
|
112
|
+
unsubscribe
|
|
113
|
+
} = actor.subscribe(handleStoreChange);
|
|
111
114
|
return unsubscribe;
|
|
112
115
|
}, [actor]);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}, [actor]);
|
|
116
|
-
var selectedSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
116
|
+
const boundGetSnapshot = React.useCallback(() => actor.getSnapshot(), [actor]);
|
|
117
|
+
const selectedSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
117
118
|
return selectedSnapshot;
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
function _typeof(obj) {
|
|
121
|
-
"@babel/helpers - typeof";
|
|
122
|
-
|
|
123
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
124
|
-
return typeof obj;
|
|
125
|
-
} : function (obj) {
|
|
126
|
-
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
127
|
-
}, _typeof(obj);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
121
|
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
131
122
|
function is(x, y) {
|
|
132
123
|
if (x === y) {
|
|
@@ -137,13 +128,13 @@ function is(x, y) {
|
|
|
137
128
|
}
|
|
138
129
|
function shallowEqual(objA, objB) {
|
|
139
130
|
if (is(objA, objB)) return true;
|
|
140
|
-
if (
|
|
131
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
141
132
|
return false;
|
|
142
133
|
}
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
const keysA = Object.keys(objA);
|
|
135
|
+
const keysB = Object.keys(objB);
|
|
145
136
|
if (keysA.length !== keysB.length) return false;
|
|
146
|
-
for (
|
|
137
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
147
138
|
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
148
139
|
return false;
|
|
149
140
|
}
|
|
@@ -152,28 +143,28 @@ function shallowEqual(objA, objB) {
|
|
|
152
143
|
}
|
|
153
144
|
|
|
154
145
|
function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
function Provider(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
146
|
+
const ReactContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
147
|
+
const OriginalProvider = ReactContext.Provider;
|
|
148
|
+
function Provider({
|
|
149
|
+
children,
|
|
150
|
+
machine: providedMachine = machine
|
|
151
|
+
}) {
|
|
152
|
+
const actor = useActorRef(providedMachine, interpreterOptions, observerOrListener);
|
|
162
153
|
return /*#__PURE__*/React__namespace.createElement(OriginalProvider, {
|
|
163
154
|
value: actor,
|
|
164
|
-
children
|
|
155
|
+
children
|
|
165
156
|
});
|
|
166
157
|
}
|
|
167
|
-
Provider.displayName =
|
|
158
|
+
Provider.displayName = `ActorProvider(${machine.id})`;
|
|
168
159
|
function useContext() {
|
|
169
|
-
|
|
160
|
+
const actor = React__namespace.useContext(ReactContext);
|
|
170
161
|
if (!actor) {
|
|
171
|
-
throw new Error(
|
|
162
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
172
163
|
}
|
|
173
164
|
return actor;
|
|
174
165
|
}
|
|
175
166
|
function useSelector$1(selector, compare) {
|
|
176
|
-
|
|
167
|
+
const actor = useContext();
|
|
177
168
|
return useSelector(actor, selector, compare);
|
|
178
169
|
}
|
|
179
170
|
return {
|
|
@@ -187,8 +178,7 @@ function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
|
187
178
|
*
|
|
188
179
|
* @deprecated Use `useActor(...)` instead.
|
|
189
180
|
*/
|
|
190
|
-
function useMachine(machine) {
|
|
191
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
181
|
+
function useMachine(machine, options = {}) {
|
|
192
182
|
return useActor(machine, options);
|
|
193
183
|
}
|
|
194
184
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
4
|
+
import { toObserver, InterpreterStatus, interpret } from 'xstate';
|
|
5
|
+
import { u as useConstant } from './useConstant-bac83df4.development.esm.js';
|
|
6
|
+
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
7
|
+
import { isActorRef } from 'xstate/actors';
|
|
8
|
+
|
|
9
|
+
function useIdleInterpreter(machine, options) {
|
|
10
|
+
{
|
|
11
|
+
const [initialMachine] = useState(machine);
|
|
12
|
+
if (machine.config !== initialMachine.config) {
|
|
13
|
+
console.warn(`Actor logic has changed between renders. This is not supported and may lead to invalid snapshots.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const actorRef = useConstant(() => {
|
|
17
|
+
return interpret(machine, options);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
21
|
+
useIsomorphicLayoutEffect(() => {
|
|
22
|
+
actorRef.behavior.options = machine.options;
|
|
23
|
+
});
|
|
24
|
+
return actorRef;
|
|
25
|
+
}
|
|
26
|
+
function useActorRef(machine, ...[options = {}, observerOrListener]) {
|
|
27
|
+
const service = useIdleInterpreter(machine, options);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!observerOrListener) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let sub = service.subscribe(toObserver(observerOrListener));
|
|
33
|
+
return () => {
|
|
34
|
+
sub.unsubscribe();
|
|
35
|
+
};
|
|
36
|
+
}, [observerOrListener]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
service.start();
|
|
39
|
+
return () => {
|
|
40
|
+
service.stop();
|
|
41
|
+
service.status = InterpreterStatus.NotStarted;
|
|
42
|
+
service._initState();
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
return service;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function identity(a) {
|
|
49
|
+
return a;
|
|
50
|
+
}
|
|
51
|
+
const isEqual = (prevState, nextState) => {
|
|
52
|
+
return prevState === nextState || nextState.changed === false;
|
|
53
|
+
};
|
|
54
|
+
function useActor(behavior, options = {}) {
|
|
55
|
+
if (isActorRef(behavior)) {
|
|
56
|
+
throw new Error(`useActor() expects actor logic (e.g. a machine), but received an ActorRef. Use the useSelector(actorRef, ...) hook instead to read the ActorRef's snapshot.`);
|
|
57
|
+
}
|
|
58
|
+
const actorRef = useIdleInterpreter(behavior, options);
|
|
59
|
+
const getSnapshot = useCallback(() => {
|
|
60
|
+
return actorRef.getSnapshot();
|
|
61
|
+
}, [actorRef]);
|
|
62
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
63
|
+
const {
|
|
64
|
+
unsubscribe
|
|
65
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
66
|
+
return unsubscribe;
|
|
67
|
+
}, [actorRef]);
|
|
68
|
+
const actorSnapshot = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
actorRef.start();
|
|
71
|
+
return () => {
|
|
72
|
+
actorRef.stop();
|
|
73
|
+
actorRef.status = InterpreterStatus.NotStarted;
|
|
74
|
+
actorRef._initState();
|
|
75
|
+
};
|
|
76
|
+
}, [actorRef]);
|
|
77
|
+
return [actorSnapshot, actorRef.send, actorRef];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function defaultCompare(a, b) {
|
|
81
|
+
return a === b;
|
|
82
|
+
}
|
|
83
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
84
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
85
|
+
const {
|
|
86
|
+
unsubscribe
|
|
87
|
+
} = actor.subscribe(handleStoreChange);
|
|
88
|
+
return unsubscribe;
|
|
89
|
+
}, [actor]);
|
|
90
|
+
const boundGetSnapshot = useCallback(() => actor.getSnapshot(), [actor]);
|
|
91
|
+
const selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
92
|
+
return selectedSnapshot;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
96
|
+
function is(x, y) {
|
|
97
|
+
if (x === y) {
|
|
98
|
+
return x !== 0 || y !== 0 || 1 / x === 1 / y;
|
|
99
|
+
} else {
|
|
100
|
+
return x !== x && y !== y;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function shallowEqual(objA, objB) {
|
|
104
|
+
if (is(objA, objB)) return true;
|
|
105
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
const keysA = Object.keys(objA);
|
|
109
|
+
const keysB = Object.keys(objB);
|
|
110
|
+
if (keysA.length !== keysB.length) return false;
|
|
111
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
112
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
120
|
+
const ReactContext = /*#__PURE__*/React.createContext(null);
|
|
121
|
+
const OriginalProvider = ReactContext.Provider;
|
|
122
|
+
function Provider({
|
|
123
|
+
children,
|
|
124
|
+
machine: providedMachine = machine
|
|
125
|
+
}) {
|
|
126
|
+
const actor = useActorRef(providedMachine, interpreterOptions, observerOrListener);
|
|
127
|
+
return /*#__PURE__*/React.createElement(OriginalProvider, {
|
|
128
|
+
value: actor,
|
|
129
|
+
children
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
Provider.displayName = `ActorProvider(${machine.id})`;
|
|
133
|
+
function useContext() {
|
|
134
|
+
const actor = React.useContext(ReactContext);
|
|
135
|
+
if (!actor) {
|
|
136
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
137
|
+
}
|
|
138
|
+
return actor;
|
|
139
|
+
}
|
|
140
|
+
function useSelector$1(selector, compare) {
|
|
141
|
+
const actor = useContext();
|
|
142
|
+
return useSelector(actor, selector, compare);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
Provider: Provider,
|
|
146
|
+
useActorRef: useContext,
|
|
147
|
+
useSelector: useSelector$1
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
*
|
|
153
|
+
* @deprecated Use `useActor(...)` instead.
|
|
154
|
+
*/
|
|
155
|
+
function useMachine(machine, options = {}) {
|
|
156
|
+
return useActor(machine, options);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export { createActorContext, shallowEqual, useActor, useActorRef, useMachine, useSelector };
|