1 | (function (global, factory) {
|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('jotai/react')) :
|
3 | typeof define === 'function' && define.amd ? define(['exports', 'react', 'jotai/react'], factory) :
|
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jotaiDevtools = {}, global.React, global.react));
|
5 | })(this, (function (exports, react$1, react) { 'use strict';
|
6 |
|
7 | function _extends() {
|
8 | _extends = Object.assign ? Object.assign.bind() : function (target) {
|
9 | for (var i = 1; i < arguments.length; i++) {
|
10 | var source = arguments[i];
|
11 | for (var key in source) {
|
12 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
13 | target[key] = source[key];
|
14 | }
|
15 | }
|
16 | }
|
17 | return target;
|
18 | };
|
19 | return _extends.apply(this, arguments);
|
20 | }
|
21 | function _unsupportedIterableToArray(o, minLen) {
|
22 | if (!o) return;
|
23 | if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
24 | var n = Object.prototype.toString.call(o).slice(8, -1);
|
25 | if (n === "Object" && o.constructor) n = o.constructor.name;
|
26 | if (n === "Map" || n === "Set") return Array.from(o);
|
27 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
28 | }
|
29 | function _arrayLikeToArray(arr, len) {
|
30 | if (len == null || len > arr.length) len = arr.length;
|
31 | for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
32 | return arr2;
|
33 | }
|
34 | function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
35 | var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
36 | if (it) return (it = it.call(o)).next.bind(it);
|
37 | if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
38 | if (it) o = it;
|
39 | var i = 0;
|
40 | return function () {
|
41 | if (i >= o.length) return {
|
42 | done: true
|
43 | };
|
44 | return {
|
45 | done: false,
|
46 | value: o[i++]
|
47 | };
|
48 | };
|
49 | }
|
50 | throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
51 | }
|
52 |
|
53 | var atomToPrintable$1 = function atomToPrintable(atom) {
|
54 | return atom.debugLabel || atom.toString();
|
55 | };
|
56 | var stateToPrintable = function stateToPrintable(_ref) {
|
57 | var store = _ref[0],
|
58 | atoms = _ref[1];
|
59 | return Object.fromEntries(atoms.flatMap(function (atom) {
|
60 | var mounted = store.dev_get_mounted == null ? void 0 : store.dev_get_mounted(atom);
|
61 | if (!mounted) {
|
62 | return [];
|
63 | }
|
64 | var dependents = mounted.t;
|
65 | var atomState = (store.dev_get_atom_state == null ? void 0 : store.dev_get_atom_state(atom)) || {};
|
66 | return [[atomToPrintable$1(atom), _extends({}, 'e' in atomState && {
|
67 | error: atomState.e
|
68 | }, 'v' in atomState && {
|
69 | value: atomState.v
|
70 | }, {
|
71 | dependents: Array.from(dependents).map(atomToPrintable$1)
|
72 | })]];
|
73 | }));
|
74 | };
|
75 | var useAtomsDebugValue = function useAtomsDebugValue(options) {
|
76 | var _options$enabled;
|
77 | var enabled = (_options$enabled = options == null ? void 0 : options.enabled) != null ? _options$enabled : true;
|
78 | var store = react.useStore(options);
|
79 | var _useState = react$1.useState([]),
|
80 | atoms = _useState[0],
|
81 | setAtoms = _useState[1];
|
82 | react$1.useEffect(function () {
|
83 | if (!enabled) {
|
84 | return;
|
85 | }
|
86 | var callback = function callback() {
|
87 | setAtoms(Array.from((store.dev_get_mounted_atoms == null ? void 0 : store.dev_get_mounted_atoms()) || []));
|
88 | };
|
89 | var unsubscribe = store.dev_subscribe_state == null ? void 0 : store.dev_subscribe_state(callback);
|
90 | callback();
|
91 | return unsubscribe;
|
92 | }, [enabled, store]);
|
93 | react$1.useDebugValue([store, atoms], stateToPrintable);
|
94 | };
|
95 |
|
96 | function useAtomDevtools(anAtom, options) {
|
97 | var _ref = options || {},
|
98 | enabled = _ref.enabled,
|
99 | name = _ref.name;
|
100 | var extension;
|
101 | try {
|
102 | extension = (enabled != null ? enabled : true) && window.__REDUX_DEVTOOLS_EXTENSION__;
|
103 | } catch (_unused) {}
|
104 | if (!extension) {
|
105 | if (enabled) {
|
106 | console.warn('Please install/enable Redux devtools extension');
|
107 | }
|
108 | }
|
109 | var _useAtom = react.useAtom(anAtom),
|
110 | value = _useAtom[0],
|
111 | setValue = _useAtom[1];
|
112 | var lastValue = react$1.useRef(value);
|
113 | var isTimeTraveling = react$1.useRef(false);
|
114 | var devtools = react$1.useRef();
|
115 | var atomName = name || anAtom.debugLabel || anAtom.toString();
|
116 | react$1.useEffect(function () {
|
117 | if (!extension) {
|
118 | return;
|
119 | }
|
120 | var setValueIfWritable = function setValueIfWritable(value) {
|
121 | if (typeof setValue === 'function') {
|
122 | setValue(value);
|
123 | return;
|
124 | }
|
125 | console.warn('[Warn] you cannot do write operations (Time-travelling, etc) in read-only atoms\n', anAtom);
|
126 | };
|
127 | devtools.current = extension.connect({
|
128 | name: atomName
|
129 | });
|
130 | var unsubscribe = devtools.current.subscribe(function (message) {
|
131 | var _message$payload3, _message$payload4;
|
132 | if (message.type === 'ACTION' && message.payload) {
|
133 | try {
|
134 | setValueIfWritable(JSON.parse(message.payload));
|
135 | } catch (e) {
|
136 | console.error('please dispatch a serializable value that JSON.parse() support\n', e);
|
137 | }
|
138 | } else if (message.type === 'DISPATCH' && message.state) {
|
139 | var _message$payload, _message$payload2;
|
140 | if (((_message$payload = message.payload) == null ? void 0 : _message$payload.type) === 'JUMP_TO_ACTION' || ((_message$payload2 = message.payload) == null ? void 0 : _message$payload2.type) === 'JUMP_TO_STATE') {
|
141 | isTimeTraveling.current = true;
|
142 | setValueIfWritable(JSON.parse(message.state));
|
143 | }
|
144 | } else if (message.type === 'DISPATCH' && ((_message$payload3 = message.payload) == null ? void 0 : _message$payload3.type) === 'COMMIT') {
|
145 | var _devtools$current;
|
146 | (_devtools$current = devtools.current) == null ? void 0 : _devtools$current.init(lastValue.current);
|
147 | } else if (message.type === 'DISPATCH' && ((_message$payload4 = message.payload) == null ? void 0 : _message$payload4.type) === 'IMPORT_STATE') {
|
148 | var _message$payload$next;
|
149 | var computedStates = ((_message$payload$next = message.payload.nextLiftedState) == null ? void 0 : _message$payload$next.computedStates) || [];
|
150 | computedStates.forEach(function (_ref2, index) {
|
151 | var state = _ref2.state;
|
152 | if (index === 0) {
|
153 | var _devtools$current2;
|
154 | (_devtools$current2 = devtools.current) == null ? void 0 : _devtools$current2.init(state);
|
155 | } else {
|
156 | setValueIfWritable(state);
|
157 | }
|
158 | });
|
159 | }
|
160 | });
|
161 | devtools.current.shouldInit = true;
|
162 | return unsubscribe;
|
163 | }, [anAtom, extension, atomName, setValue]);
|
164 | react$1.useEffect(function () {
|
165 | if (!devtools.current) {
|
166 | return;
|
167 | }
|
168 | lastValue.current = value;
|
169 | if (devtools.current.shouldInit) {
|
170 | devtools.current.init(value);
|
171 | devtools.current.shouldInit = false;
|
172 | } else if (isTimeTraveling.current) {
|
173 | isTimeTraveling.current = false;
|
174 | } else {
|
175 | devtools.current.send(atomName + " - " + new Date().toLocaleString(), value);
|
176 | }
|
177 | }, [anAtom, extension, atomName, value]);
|
178 | }
|
179 |
|
180 | var isEqualAtomsValues = function isEqualAtomsValues(left, right) {
|
181 | return left.size === right.size && Array.from(left).every(function (_ref) {
|
182 | var left = _ref[0],
|
183 | v = _ref[1];
|
184 | return Object.is(right.get(left), v);
|
185 | });
|
186 | };
|
187 | var isEqualAtomsDependents = function isEqualAtomsDependents(left, right) {
|
188 | return left.size === right.size && Array.from(left).every(function (_ref2) {
|
189 | var a = _ref2[0],
|
190 | dLeft = _ref2[1];
|
191 | var dRight = right.get(a);
|
192 | return dRight && dLeft.size === dRight.size && Array.from(dLeft).every(function (d) {
|
193 | return dRight.has(d);
|
194 | });
|
195 | });
|
196 | };
|
197 | function useAtomsSnapshot(options) {
|
198 | var store = react.useStore(options);
|
199 | var _useState = react$1.useState(function () {
|
200 | return {
|
201 | values: new Map(),
|
202 | dependents: new Map()
|
203 | };
|
204 | }),
|
205 | atomsSnapshot = _useState[0],
|
206 | setAtomsSnapshot = _useState[1];
|
207 | react$1.useEffect(function () {
|
208 | if (!store.dev_subscribe_state) return;
|
209 | var prevValues = new Map();
|
210 | var prevDependents = new Map();
|
211 | var callback = function callback() {
|
212 | var values = new Map();
|
213 | var dependents = new Map();
|
214 | for (var _iterator = _createForOfIteratorHelperLoose(store.dev_get_mounted_atoms() || []), _step; !(_step = _iterator()).done;) {
|
215 | var atom = _step.value;
|
216 | var atomState = store.dev_get_atom_state(atom);
|
217 | if (atomState) {
|
218 | if ('v' in atomState) {
|
219 | values.set(atom, atomState.v);
|
220 | }
|
221 | }
|
222 | var mounted = store.dev_get_mounted(atom);
|
223 | if (mounted) {
|
224 | dependents.set(atom, mounted.t);
|
225 | }
|
226 | }
|
227 | if (isEqualAtomsValues(prevValues, values) && isEqualAtomsDependents(prevDependents, dependents)) {
|
228 | return;
|
229 | }
|
230 | prevValues = values;
|
231 | prevDependents = dependents;
|
232 | setAtomsSnapshot({
|
233 | values: values,
|
234 | dependents: dependents
|
235 | });
|
236 | };
|
237 | var unsubscribe = store.dev_subscribe_state(callback);
|
238 | callback();
|
239 | return unsubscribe;
|
240 | }, [store]);
|
241 | return atomsSnapshot;
|
242 | }
|
243 |
|
244 | function useGotoAtomsSnapshot(options) {
|
245 | var store = react.useStore(options);
|
246 | return react$1.useCallback(function (snapshot) {
|
247 | if (store.dev_subscribe_state) {
|
248 | store.res(snapshot.values);
|
249 | }
|
250 | }, [store]);
|
251 | }
|
252 |
|
253 | var atomToPrintable = function atomToPrintable(atom) {
|
254 | return atom.debugLabel ? atom + ":" + atom.debugLabel : "" + atom;
|
255 | };
|
256 | var getDevtoolsState = function getDevtoolsState(atomsSnapshot) {
|
257 | var values = {};
|
258 | atomsSnapshot.values.forEach(function (v, atom) {
|
259 | values[atomToPrintable(atom)] = v;
|
260 | });
|
261 | var dependents = {};
|
262 | atomsSnapshot.dependents.forEach(function (d, atom) {
|
263 | dependents[atomToPrintable(atom)] = Array.from(d).map(atomToPrintable);
|
264 | });
|
265 | return {
|
266 | values: values,
|
267 | dependents: dependents
|
268 | };
|
269 | };
|
270 | function useAtomsDevtools(name, options) {
|
271 | var _ref = options || {},
|
272 | enabled = _ref.enabled;
|
273 | var extension;
|
274 | try {
|
275 | extension = (enabled != null ? enabled : true) && window.__REDUX_DEVTOOLS_EXTENSION__;
|
276 | } catch (_unused) {}
|
277 | if (!extension) {
|
278 | if (enabled) {
|
279 | console.warn('Please install/enable Redux devtools extension');
|
280 | }
|
281 | }
|
282 | var atomsSnapshot = useAtomsSnapshot();
|
283 | var goToSnapshot = useGotoAtomsSnapshot();
|
284 | var isTimeTraveling = react$1.useRef(false);
|
285 | var isRecording = react$1.useRef(true);
|
286 | var devtools = react$1.useRef();
|
287 | var snapshots = react$1.useRef([]);
|
288 | react$1.useEffect(function () {
|
289 | if (!extension) {
|
290 | return;
|
291 | }
|
292 | var getSnapshotAt = function getSnapshotAt(index) {
|
293 | if (index === void 0) {
|
294 | index = snapshots.current.length - 1;
|
295 | }
|
296 | var snapshot = snapshots.current[index >= 0 ? index : 0];
|
297 | if (!snapshot) {
|
298 | throw new Error('snaphost index out of bounds');
|
299 | }
|
300 | return snapshot;
|
301 | };
|
302 | var connection = extension.connect({
|
303 | name: name
|
304 | });
|
305 | var devtoolsUnsubscribe = connection.subscribe(function (message) {
|
306 | var _message$payload;
|
307 | switch (message.type) {
|
308 | case 'DISPATCH':
|
309 | switch ((_message$payload = message.payload) == null ? void 0 : _message$payload.type) {
|
310 | case 'RESET':
|
311 | break;
|
312 | case 'COMMIT':
|
313 | connection.init(getDevtoolsState(getSnapshotAt()));
|
314 | snapshots.current = [];
|
315 | break;
|
316 | case 'JUMP_TO_ACTION':
|
317 | case 'JUMP_TO_STATE':
|
318 | isTimeTraveling.current = true;
|
319 | goToSnapshot(getSnapshotAt(message.payload.actionId - 1));
|
320 | break;
|
321 | case 'PAUSE_RECORDING':
|
322 | isRecording.current = !isRecording.current;
|
323 | break;
|
324 | }
|
325 | }
|
326 | });
|
327 | devtools.current = connection;
|
328 | devtools.current.shouldInit = true;
|
329 | return function () {
|
330 | extension.disconnect();
|
331 | devtoolsUnsubscribe == null ? void 0 : devtoolsUnsubscribe();
|
332 | };
|
333 | }, [extension, goToSnapshot, name]);
|
334 | react$1.useEffect(function () {
|
335 | if (!devtools.current) {
|
336 | return;
|
337 | }
|
338 | if (devtools.current.shouldInit) {
|
339 | devtools.current.init(undefined);
|
340 | devtools.current.shouldInit = false;
|
341 | return;
|
342 | }
|
343 | if (isTimeTraveling.current) {
|
344 | isTimeTraveling.current = false;
|
345 | } else if (isRecording.current) {
|
346 | snapshots.current.push(atomsSnapshot);
|
347 | devtools.current.send({
|
348 | type: "" + snapshots.current.length,
|
349 | updatedAt: new Date().toLocaleString()
|
350 | }, getDevtoolsState(atomsSnapshot));
|
351 | }
|
352 | }, [atomsSnapshot]);
|
353 | }
|
354 |
|
355 | exports.useAtomDevtools = useAtomDevtools;
|
356 | exports.useAtomsDebugValue = useAtomsDebugValue;
|
357 | exports.useAtomsDevtools = useAtomsDevtools;
|
358 | exports.useAtomsSnapshot = useAtomsSnapshot;
|
359 | exports.useGotoAtomsSnapshot = useGotoAtomsSnapshot;
|
360 |
|
361 | }));
|