UNPKG

13.9 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var react = require('react');
6var jotai = require('jotai');
7
8function useAtomDevtools(anAtom, options, deprecatedScope) {
9 if (typeof options === 'string' || typeof deprecatedScope !== 'undefined') {
10 console.warn('DEPRECATED [useAtomDevtools] use DevtoolOptions');
11 options = {
12 name: options,
13 scope: deprecatedScope
14 };
15 }
16
17 var _ref = options || {},
18 enabled = _ref.enabled,
19 name = _ref.name,
20 scope = _ref.scope;
21
22 var extension;
23
24 try {
25 extension = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
26 } catch (_unused) {}
27
28 if (!extension) {
29 if (process.env.NODE_ENV !== "production" && enabled) {
30 console.warn('Please install/enable Redux devtools extension');
31 }
32 }
33
34 var _useAtom = jotai.useAtom(anAtom, scope),
35 value = _useAtom[0],
36 setValue = _useAtom[1];
37
38 var lastValue = react.useRef(value);
39 var isTimeTraveling = react.useRef(false);
40 var devtools = react.useRef();
41 var atomName = name || anAtom.debugLabel || anAtom.toString();
42 react.useEffect(function () {
43 if (!extension) {
44 return;
45 }
46
47 var setValueIfWritable = function setValueIfWritable(value) {
48 if (typeof setValue === 'function') {
49 setValue(value);
50 return;
51 }
52
53 console.warn('[Warn] you cannot do write operations (Time-travelling, etc) in read-only atoms\n', anAtom);
54 };
55
56 devtools.current = extension.connect({
57 name: atomName
58 });
59 var unsubscribe = devtools.current.subscribe(function (message) {
60 var _message$payload3, _message$payload4;
61
62 if (message.type === 'ACTION' && message.payload) {
63 try {
64 setValueIfWritable(JSON.parse(message.payload));
65 } catch (e) {
66 console.error('please dispatch a serializable value that JSON.parse() support\n', e);
67 }
68 } else if (message.type === 'DISPATCH' && message.state) {
69 var _message$payload, _message$payload2;
70
71 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') {
72 isTimeTraveling.current = true;
73 setValueIfWritable(JSON.parse(message.state));
74 }
75 } else if (message.type === 'DISPATCH' && ((_message$payload3 = message.payload) == null ? void 0 : _message$payload3.type) === 'COMMIT') {
76 var _devtools$current;
77
78 (_devtools$current = devtools.current) == null ? void 0 : _devtools$current.init(lastValue.current);
79 } else if (message.type === 'DISPATCH' && ((_message$payload4 = message.payload) == null ? void 0 : _message$payload4.type) === 'IMPORT_STATE') {
80 var _message$payload$next;
81
82 var computedStates = ((_message$payload$next = message.payload.nextLiftedState) == null ? void 0 : _message$payload$next.computedStates) || [];
83 computedStates.forEach(function (_ref2, index) {
84 var state = _ref2.state;
85
86 if (index === 0) {
87 var _devtools$current2;
88
89 (_devtools$current2 = devtools.current) == null ? void 0 : _devtools$current2.init(state);
90 } else {
91 setValueIfWritable(state);
92 }
93 });
94 }
95 });
96 devtools.current.shouldInit = true;
97 return unsubscribe;
98 }, [anAtom, extension, atomName, setValue]);
99 react.useEffect(function () {
100 if (!devtools.current) {
101 return;
102 }
103
104 lastValue.current = value;
105
106 if (devtools.current.shouldInit) {
107 devtools.current.init(value);
108 devtools.current.shouldInit = false;
109 } else if (isTimeTraveling.current) {
110 isTimeTraveling.current = false;
111 } else {
112 devtools.current.send(atomName + " - " + new Date().toLocaleString(), value);
113 }
114 }, [anAtom, extension, atomName, value]);
115}
116
117function _unsupportedIterableToArray(o, minLen) {
118 if (!o) return;
119 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
120 var n = Object.prototype.toString.call(o).slice(8, -1);
121 if (n === "Object" && o.constructor) n = o.constructor.name;
122 if (n === "Map" || n === "Set") return Array.from(o);
123 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
124}
125
126function _arrayLikeToArray(arr, len) {
127 if (len == null || len > arr.length) len = arr.length;
128
129 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
130
131 return arr2;
132}
133
134function _createForOfIteratorHelperLoose(o, allowArrayLike) {
135 var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
136 if (it) return (it = it.call(o)).next.bind(it);
137
138 if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
139 if (it) o = it;
140 var i = 0;
141 return function () {
142 if (i >= o.length) return {
143 done: true
144 };
145 return {
146 done: false,
147 value: o[i++]
148 };
149 };
150 }
151
152 throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
153}
154
155var RESTORE_ATOMS = 'h';
156var DEV_SUBSCRIBE_STATE = 'n';
157var DEV_GET_MOUNTED_ATOMS = 'l';
158var DEV_GET_ATOM_STATE = 'a';
159var DEV_GET_MOUNTED = 'm';
160
161var createAtomsSnapshot = function createAtomsSnapshot(store, atoms) {
162 var tuples = atoms.map(function (atom) {
163 var _store$DEV_GET_ATOM_S, _store$DEV_GET_ATOM_S2;
164
165 var atomState = (_store$DEV_GET_ATOM_S = (_store$DEV_GET_ATOM_S2 = store[DEV_GET_ATOM_STATE]) == null ? void 0 : _store$DEV_GET_ATOM_S2.call(store, atom)) != null ? _store$DEV_GET_ATOM_S : {};
166 return [atom, 'v' in atomState ? atomState.v : undefined];
167 });
168 return new Map(tuples);
169};
170
171function useAtomsSnapshot(scope) {
172 var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(scope);
173 var scopeContainer = react.useContext(ScopeContext);
174 var store = scopeContainer.s;
175
176 if (!store[DEV_SUBSCRIBE_STATE]) {
177 throw new Error('useAtomsSnapshot can only be used in dev mode.');
178 }
179
180 var _useState = react.useState(function () {
181 return new Map();
182 }),
183 atomsSnapshot = _useState[0],
184 setAtomsSnapshot = _useState[1];
185
186 react.useEffect(function () {
187 var _store$DEV_SUBSCRIBE_;
188
189 var callback = function callback() {
190 var _store$DEV_GET_MOUNTE;
191
192 var atoms = Array.from(((_store$DEV_GET_MOUNTE = store[DEV_GET_MOUNTED_ATOMS]) == null ? void 0 : _store$DEV_GET_MOUNTE.call(store)) || []);
193 setAtomsSnapshot(createAtomsSnapshot(store, atoms));
194 };
195
196 var unsubscribe = (_store$DEV_SUBSCRIBE_ = store[DEV_SUBSCRIBE_STATE]) == null ? void 0 : _store$DEV_SUBSCRIBE_.call(store, callback);
197 callback();
198 return unsubscribe;
199 }, [store]);
200 return atomsSnapshot;
201}
202
203function useGotoAtomsSnapshot(scope) {
204 var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(scope);
205 var scopeContainer = react.useContext(ScopeContext);
206 var store = scopeContainer.s;
207
208 if (!store[DEV_SUBSCRIBE_STATE]) {
209 throw new Error('useGotoAtomsSnapshot can only be used in dev mode.');
210 }
211
212 return react.useCallback(function (values) {
213 store[RESTORE_ATOMS](values);
214 }, [store]);
215}
216
217var isEqualAtomsValues = function isEqualAtomsValues(left, right) {
218 return left.size === right.size && Array.from(left).every(function (_ref) {
219 var left = _ref[0],
220 v = _ref[1];
221 return Object.is(right.get(left), v);
222 });
223};
224
225var isEqualAtomsDependents = function isEqualAtomsDependents(left, right) {
226 return left.size === right.size && Array.from(left).every(function (_ref2) {
227 var a = _ref2[0],
228 dLeft = _ref2[1];
229 var dRight = right.get(a);
230 return dRight && dLeft.size === dRight.size && Array.from(dLeft).every(function (d) {
231 return dRight.has(d);
232 });
233 });
234};
235
236var atomToPrintable = function atomToPrintable(atom) {
237 return atom.debugLabel ? atom + ":" + atom.debugLabel : "" + atom;
238};
239
240var getDevtoolsState = function getDevtoolsState(atomsSnapshot) {
241 var values = {};
242 atomsSnapshot.values.forEach(function (v, atom) {
243 values[atomToPrintable(atom)] = v;
244 });
245 var dependents = {};
246 atomsSnapshot.dependents.forEach(function (d, atom) {
247 dependents[atomToPrintable(atom)] = Array.from(d).map(atomToPrintable);
248 });
249 return {
250 values: values,
251 dependents: dependents
252 };
253};
254
255function useAtomsDevtools(name, options) {
256 if (typeof options !== 'undefined' && typeof options !== 'object') {
257 console.warn('DEPRECATED [useAtomsDevtools] use DevtoolsOptions');
258 options = {
259 scope: options
260 };
261 }
262
263 var _ref3 = options || {},
264 enabled = _ref3.enabled,
265 scope = _ref3.scope;
266
267 var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(scope);
268
269 var _useContext = react.useContext(ScopeContext),
270 store = _useContext.s,
271 versionedWrite = _useContext.w;
272
273 var extension;
274
275 try {
276 extension = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
277 } catch (_unused) {}
278
279 if (!extension) {
280 if (process.env.NODE_ENV !== "production" && enabled) {
281 console.warn('Please install/enable Redux devtools extension');
282 }
283 }
284
285 if (extension && !store[DEV_SUBSCRIBE_STATE]) {
286 throw new Error('useAtomsDevtools can only be used in dev mode.');
287 }
288
289 var _useState = react.useState(function () {
290 return {
291 values: new Map(),
292 dependents: new Map()
293 };
294 }),
295 atomsSnapshot = _useState[0],
296 setAtomsSnapshot = _useState[1];
297
298 react.useEffect(function () {
299 var _store$DEV_SUBSCRIBE_;
300
301 if (!extension) {
302 return;
303 }
304
305 var callback = function callback() {
306 var values = new Map();
307 var dependents = new Map();
308
309 for (var _iterator = _createForOfIteratorHelperLoose(((_store$DEV_GET_MOUNTE = store[DEV_GET_MOUNTED_ATOMS]) == null ? void 0 : _store$DEV_GET_MOUNTE.call(store)) || []), _step; !(_step = _iterator()).done;) {
310 var _store$DEV_GET_MOUNTE, _store$DEV_GET_ATOM_S, _store$DEV_GET_MOUNTE2;
311
312 var atom = _step.value;
313 var atomState = (_store$DEV_GET_ATOM_S = store[DEV_GET_ATOM_STATE]) == null ? void 0 : _store$DEV_GET_ATOM_S.call(store, atom);
314
315 if (atomState) {
316 if (atomState.r === atomState.i) {
317 return;
318 }
319
320 if ('v' in atomState) {
321 values.set(atom, atomState.v);
322 }
323 }
324
325 var mounted = (_store$DEV_GET_MOUNTE2 = store[DEV_GET_MOUNTED]) == null ? void 0 : _store$DEV_GET_MOUNTE2.call(store, atom);
326
327 if (mounted) {
328 dependents.set(atom, mounted.t);
329 }
330 }
331
332 setAtomsSnapshot(function (prev) {
333 if (isEqualAtomsValues(prev.values, values) && isEqualAtomsDependents(prev.dependents, dependents)) {
334 return prev;
335 }
336
337 return {
338 values: values,
339 dependents: dependents
340 };
341 });
342 };
343
344 var unsubscribe = (_store$DEV_SUBSCRIBE_ = store[DEV_SUBSCRIBE_STATE]) == null ? void 0 : _store$DEV_SUBSCRIBE_.call(store, callback);
345 callback();
346 return unsubscribe;
347 }, [extension, store]);
348 var goToSnapshot = react.useCallback(function (snapshot) {
349 var values = snapshot.values;
350
351 if (versionedWrite) {
352 versionedWrite(function (version) {
353 store[RESTORE_ATOMS](values, version);
354 });
355 } else {
356 store[RESTORE_ATOMS](values);
357 }
358 }, [store, versionedWrite]);
359 var isTimeTraveling = react.useRef(false);
360 var isRecording = react.useRef(true);
361 var devtools = react.useRef();
362 var snapshots = react.useRef([]);
363 react.useEffect(function () {
364 if (!extension) {
365 return;
366 }
367
368 var getSnapshotAt = function getSnapshotAt(index) {
369 if (index === void 0) {
370 index = snapshots.current.length - 1;
371 }
372
373 var snapshot = snapshots.current[index >= 0 ? index : 0];
374
375 if (!snapshot) {
376 throw new Error('snaphost index out of bounds');
377 }
378
379 return snapshot;
380 };
381
382 var connection = extension.connect({
383 name: name
384 });
385 var devtoolsUnsubscribe = connection.subscribe(function (message) {
386 var _message$payload;
387
388 switch (message.type) {
389 case 'DISPATCH':
390 switch ((_message$payload = message.payload) == null ? void 0 : _message$payload.type) {
391 case 'RESET':
392 break;
393
394 case 'COMMIT':
395 connection.init(getDevtoolsState(getSnapshotAt()));
396 snapshots.current = [];
397 break;
398
399 case 'JUMP_TO_ACTION':
400 case 'JUMP_TO_STATE':
401 isTimeTraveling.current = true;
402 goToSnapshot(getSnapshotAt(message.payload.actionId - 1));
403 break;
404
405 case 'PAUSE_RECORDING':
406 isRecording.current = !isRecording.current;
407 break;
408 }
409
410 }
411 });
412 devtools.current = connection;
413 devtools.current.shouldInit = true;
414 return devtoolsUnsubscribe;
415 }, [extension, goToSnapshot, name]);
416 react.useEffect(function () {
417 if (!devtools.current) {
418 return;
419 }
420
421 if (devtools.current.shouldInit) {
422 devtools.current.init(undefined);
423 devtools.current.shouldInit = false;
424 return;
425 }
426
427 if (isTimeTraveling.current) {
428 isTimeTraveling.current = false;
429 } else if (isRecording.current) {
430 snapshots.current.push(atomsSnapshot);
431 devtools.current.send({
432 type: "" + snapshots.current.length,
433 updatedAt: new Date().toLocaleString()
434 }, getDevtoolsState(atomsSnapshot));
435 }
436 }, [atomsSnapshot]);
437}
438
439exports.useAtomDevtools = useAtomDevtools;
440exports.useAtomsDevtools = useAtomsDevtools;
441exports.useAtomsSnapshot = useAtomsSnapshot;
442exports.useGotoAtomsSnapshot = useGotoAtomsSnapshot;