UNPKG

13.7 kBJavaScriptView Raw
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}));