1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | var react = require('react');
|
6 | var useContextSelector = require('use-context-selector');
|
7 |
|
8 | function _extends() {
|
9 | _extends = Object.assign || function (target) {
|
10 | for (var i = 1; i < arguments.length; i++) {
|
11 | var source = arguments[i];
|
12 |
|
13 | for (var key in source) {
|
14 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
15 | target[key] = source[key];
|
16 | }
|
17 | }
|
18 | }
|
19 |
|
20 | return target;
|
21 | };
|
22 |
|
23 | return _extends.apply(this, arguments);
|
24 | }
|
25 |
|
26 | var isSSR = typeof window === 'undefined' || /ServerSideRendering/.test(window.navigator && window.navigator.userAgent);
|
27 | var useIsoLayoutEffect = isSSR ? function (fn) {
|
28 | return fn();
|
29 | } : react.useLayoutEffect;
|
30 |
|
31 | var appendMap = function appendMap(dst, src) {
|
32 | src.forEach(function (v, k) {
|
33 | dst.set(k, v);
|
34 | });
|
35 | return dst;
|
36 | };
|
37 |
|
38 |
|
39 | var concatMap = function concatMap(src1, src2) {
|
40 | return appendMap(new Map(src1), src2);
|
41 | };
|
42 |
|
43 |
|
44 | var deleteMapItem = function deleteMapItem(src, key) {
|
45 | var dst = new Map(src);
|
46 | dst.delete(key);
|
47 | return dst;
|
48 | };
|
49 |
|
50 | var warningObject = new Proxy({}, {
|
51 | get: function get() {
|
52 | throw new Error('Please use <Provider>');
|
53 | },
|
54 | apply: function apply() {
|
55 | throw new Error('Please use <Provider>');
|
56 | }
|
57 | });
|
58 |
|
59 | var addDependent = function addDependent(dependentsMap, atom, dependent) {
|
60 | var dependents = dependentsMap.get(atom);
|
61 |
|
62 | if (!dependents) {
|
63 | dependents = new Set();
|
64 | dependentsMap.set(atom, dependents);
|
65 | }
|
66 |
|
67 | dependents.add(dependent);
|
68 | };
|
69 |
|
70 | var deleteDependent = function deleteDependent(dependentsMap, dependent) {
|
71 | dependentsMap.forEach(function (dependents) {
|
72 | dependents.delete(dependent);
|
73 | });
|
74 | };
|
75 |
|
76 | var setDependencies = function setDependencies(dependentsMap, atom, dependencies) {
|
77 | deleteDependent(dependentsMap, atom);
|
78 | dependencies.forEach(function (dependency) {
|
79 | addDependent(dependentsMap, dependency, atom);
|
80 | });
|
81 | };
|
82 |
|
83 | var listDependents = function listDependents(dependentsMap, atom, excludeSelf) {
|
84 | var dependents = new Set(dependentsMap.get(atom));
|
85 |
|
86 | if (excludeSelf) {
|
87 | dependents.delete(atom);
|
88 | }
|
89 |
|
90 | return dependents;
|
91 | };
|
92 |
|
93 | var initialState = new Map();
|
94 |
|
95 | var getAtomState = function getAtomState(atom, state, tmpState) {
|
96 | var atomState = tmpState && tmpState.get(atom) || state.get(atom);
|
97 |
|
98 | if (!atomState) {
|
99 | throw new Error('atom state not found. possibly a bug.');
|
100 | }
|
101 |
|
102 | return atomState;
|
103 | };
|
104 |
|
105 | var getAtomStateValue = function getAtomStateValue(atom, state, tmpState) {
|
106 | var atomState = tmpState && tmpState.get(atom) || state.get(atom);
|
107 | return atomState ? atomState.value : atom.init;
|
108 | };
|
109 |
|
110 | var readAtom = function readAtom(state, readingAtom, setState, dependentsMap, readPendingMap) {
|
111 | var readAtomValue = function readAtomValue(prevState, atom) {
|
112 | var partialState = new Map();
|
113 | var atomState = prevState.get(atom);
|
114 |
|
115 | if (atomState) {
|
116 | return [atomState, partialState];
|
117 | }
|
118 |
|
119 | var error = undefined;
|
120 | var promise = undefined;
|
121 | var value = null;
|
122 | var dependencies = new Set();
|
123 | var isSync = true;
|
124 |
|
125 | try {
|
126 | var promiseOrValue = atom.read(function (a) {
|
127 | if (dependencies) {
|
128 | dependencies.add(a);
|
129 | } else {
|
130 | addDependent(dependentsMap, a, atom);
|
131 | }
|
132 |
|
133 | if (a !== atom) {
|
134 | var _readAtomValue = readAtomValue(concatMap(prevState, partialState), a),
|
135 | _nextAtomState = _readAtomValue[0],
|
136 | nextPartialState = _readAtomValue[1];
|
137 |
|
138 | if (isSync) {
|
139 | appendMap(partialState, nextPartialState);
|
140 | } else {
|
141 | setState(function (prev) {
|
142 | return concatMap(prev, nextPartialState);
|
143 | });
|
144 | }
|
145 |
|
146 | if (_nextAtomState.readE) {
|
147 | throw _nextAtomState.readE;
|
148 | }
|
149 |
|
150 | if (_nextAtomState.readP) {
|
151 | throw _nextAtomState.readP;
|
152 | }
|
153 |
|
154 | return _nextAtomState.value;
|
155 | }
|
156 |
|
157 |
|
158 | var aState = partialState.get(a) || prevState.get(a);
|
159 |
|
160 | if (aState) {
|
161 | if (aState.readP) {
|
162 | throw aState.readP;
|
163 | }
|
164 |
|
165 | return aState.value;
|
166 | }
|
167 |
|
168 | return a.init;
|
169 | });
|
170 |
|
171 | if (promiseOrValue instanceof Promise) {
|
172 | promise = promiseOrValue.then(function (value) {
|
173 | var _prev$get;
|
174 |
|
175 | setDependencies(dependentsMap, atom, dependencies);
|
176 | dependencies = null;
|
177 | var prev = readPendingMap.get(atom);
|
178 |
|
179 | if (prev && ((_prev$get = prev.get(atom)) == null ? void 0 : _prev$get.readP) === promise) {
|
180 | readPendingMap.set(atom, deleteMapItem(prev, atom));
|
181 | }
|
182 |
|
183 | setState(function (prev) {
|
184 | return new Map(prev).set(atom, {
|
185 | value: value
|
186 | });
|
187 | });
|
188 | }).catch(function (e) {
|
189 | var _prev$get2;
|
190 |
|
191 | var prev = readPendingMap.get(atom);
|
192 |
|
193 | if (prev && ((_prev$get2 = prev.get(atom)) == null ? void 0 : _prev$get2.readP) === promise) {
|
194 | readPendingMap.set(atom, deleteMapItem(prev, atom));
|
195 | }
|
196 |
|
197 | setState(function (prev) {
|
198 | return new Map(prev).set(atom, {
|
199 | value: getAtomStateValue(atom, prev),
|
200 | readE: e instanceof Error ? e : new Error(e)
|
201 | });
|
202 | });
|
203 | });
|
204 | } else {
|
205 | setDependencies(dependentsMap, atom, dependencies);
|
206 | dependencies = null;
|
207 | value = promiseOrValue;
|
208 | }
|
209 | } catch (errorOrPromise) {
|
210 | if (errorOrPromise instanceof Promise) {
|
211 | promise = errorOrPromise;
|
212 | } else if (errorOrPromise instanceof Error) {
|
213 | error = errorOrPromise;
|
214 | } else {
|
215 | error = new Error(errorOrPromise);
|
216 | }
|
217 | }
|
218 |
|
219 | var nextAtomState = {
|
220 | readE: error,
|
221 | readP: promise,
|
222 | value: promise ? atom.init : value
|
223 | };
|
224 | partialState.set(atom, nextAtomState);
|
225 | isSync = false;
|
226 | return [nextAtomState, partialState];
|
227 | };
|
228 |
|
229 | var prevPartialState = readPendingMap.get(readingAtom);
|
230 |
|
231 | var _readAtomValue2 = readAtomValue(prevPartialState ? concatMap(state, prevPartialState) : state, readingAtom),
|
232 | atomState = _readAtomValue2[0],
|
233 | partialState = _readAtomValue2[1];
|
234 |
|
235 | readPendingMap.set(readingAtom, prevPartialState ? concatMap(prevPartialState, partialState) : partialState);
|
236 | return atomState;
|
237 | };
|
238 |
|
239 | var addAtom = function addAtom(id, atom, setState, dependentsMap, readPendingMap) {
|
240 | addDependent(dependentsMap, atom, id);
|
241 | var partialState = readPendingMap.get(atom);
|
242 |
|
243 | if (partialState) {
|
244 | readPendingMap.delete(atom);
|
245 | setState(function (prev) {
|
246 | return concatMap(prev, partialState);
|
247 | });
|
248 | }
|
249 | };
|
250 |
|
251 | var delAtom = function delAtom(id, setGcCount, dependentsMap) {
|
252 | deleteDependent(dependentsMap, id);
|
253 | setGcCount(function (c) {
|
254 | return c + 1;
|
255 | });
|
256 | };
|
257 |
|
258 | var gcAtom = function gcAtom(state, setState, dependentsMap) {
|
259 | var nextState = new Map(state);
|
260 | var deleted;
|
261 |
|
262 | do {
|
263 | deleted = false;
|
264 | nextState.forEach(function (_atomState, atom) {
|
265 | var _dependentsMap$get;
|
266 |
|
267 | var isEmpty = ((_dependentsMap$get = dependentsMap.get(atom)) == null ? void 0 : _dependentsMap$get.size) === 0;
|
268 |
|
269 | if (isEmpty) {
|
270 | nextState.delete(atom);
|
271 | dependentsMap.delete(atom);
|
272 | deleted = true;
|
273 | }
|
274 | });
|
275 | } while (deleted);
|
276 |
|
277 | if (nextState.size !== state.size) {
|
278 | setState(nextState);
|
279 | }
|
280 | };
|
281 |
|
282 | var writeAtom = function writeAtom(updatingAtom, update, setState, dependentsMap, addWriteThunk) {
|
283 | var pendingPromises = [];
|
284 |
|
285 | var updateDependentsState = function updateDependentsState(prevState, atom) {
|
286 | var partialState = new Map();
|
287 | listDependents(dependentsMap, atom, true).forEach(function (dependent) {
|
288 | if (typeof dependent === 'symbol') return;
|
289 | var dependencies = new Set();
|
290 |
|
291 | try {
|
292 | var promiseOrValue = dependent.read(function (a) {
|
293 | if (dependencies) {
|
294 | dependencies.add(a);
|
295 | } else {
|
296 | addDependent(dependentsMap, a, dependent);
|
297 | }
|
298 |
|
299 | var s = getAtomState(a, prevState);
|
300 |
|
301 | if (s.readE) {
|
302 | throw s.readE;
|
303 | }
|
304 |
|
305 | return s.value;
|
306 | });
|
307 |
|
308 | if (promiseOrValue instanceof Promise) {
|
309 | var promise = promiseOrValue.then(function (value) {
|
310 | setDependencies(dependentsMap, dependent, dependencies);
|
311 | dependencies = null;
|
312 | var nextAtomState = {
|
313 | value: value
|
314 | };
|
315 | setState(function (prev) {
|
316 | var _prev$get3;
|
317 |
|
318 | var prevPromise = (_prev$get3 = prev.get(dependent)) == null ? void 0 : _prev$get3.readP;
|
319 |
|
320 | if (prevPromise && prevPromise !== promise) {
|
321 |
|
322 | return prev;
|
323 | }
|
324 |
|
325 | var nextState = new Map(prev).set(dependent, nextAtomState);
|
326 | var nextPartialState = updateDependentsState(nextState, dependent);
|
327 | return appendMap(nextState, nextPartialState);
|
328 | });
|
329 | }).catch(function (e) {
|
330 | setState(function (prev) {
|
331 | return new Map(prev).set(dependent, {
|
332 | value: getAtomStateValue(dependent, prev),
|
333 | readE: e instanceof Error ? e : new Error(e)
|
334 | });
|
335 | });
|
336 | });
|
337 | partialState.set(dependent, {
|
338 | value: getAtomStateValue(dependent, prevState),
|
339 | readP: promise
|
340 | });
|
341 | } else {
|
342 | setDependencies(dependentsMap, dependent, dependencies);
|
343 | dependencies = null;
|
344 | partialState.set(dependent, {
|
345 | value: promiseOrValue
|
346 | });
|
347 | appendMap(partialState, updateDependentsState(concatMap(prevState, partialState), dependent));
|
348 | }
|
349 | } catch (e) {
|
350 | partialState.set(dependent, {
|
351 | value: getAtomStateValue(dependent, prevState),
|
352 | readE: e instanceof Error ? e : new Error(e)
|
353 | });
|
354 | appendMap(partialState, updateDependentsState(concatMap(prevState, partialState), dependent));
|
355 | }
|
356 | });
|
357 | return partialState;
|
358 | };
|
359 |
|
360 | var updateAtomState = function updateAtomState(prevState, atom, update) {
|
361 | var prevAtomState = prevState.get(atom);
|
362 |
|
363 | if (prevAtomState && prevAtomState.writeP) {
|
364 | var promise = prevAtomState.writeP.then(function () {
|
365 | addWriteThunk(function (prev) {
|
366 | var nextPartialState = updateAtomState(prev, atom, update);
|
367 |
|
368 | if (nextPartialState) {
|
369 | return concatMap(prevState, nextPartialState);
|
370 | }
|
371 |
|
372 | return prev;
|
373 | });
|
374 | });
|
375 | pendingPromises.push(promise);
|
376 | return null;
|
377 | }
|
378 |
|
379 | var partialState = new Map();
|
380 | var isSync = true;
|
381 |
|
382 | try {
|
383 | var promiseOrVoid = atom.write(function (a) {
|
384 | if (process.env.NODE_ENV !== 'production') {
|
385 | var s = prevState.get(a);
|
386 |
|
387 | if (s && s.readP) {
|
388 | console.log('Reading pending atom state in write operation. Not sure how to deal with it. Returning stale vaule for', a);
|
389 | }
|
390 | }
|
391 |
|
392 | return getAtomStateValue(a, prevState, partialState);
|
393 | }, function (a, v) {
|
394 | if (a === atom) {
|
395 | var nextAtomState = {
|
396 | value: v
|
397 | };
|
398 |
|
399 | if (isSync) {
|
400 | partialState.set(a, nextAtomState);
|
401 | appendMap(partialState, updateDependentsState(concatMap(prevState, partialState), a));
|
402 | } else {
|
403 | setState(function (prev) {
|
404 | var nextState = new Map(prev).set(a, nextAtomState);
|
405 | var nextPartialState = updateDependentsState(nextState, a);
|
406 | return appendMap(nextState, nextPartialState);
|
407 | });
|
408 | }
|
409 | } else {
|
410 | if (isSync) {
|
411 | var nextPartialState = updateAtomState(concatMap(prevState, partialState), a, v);
|
412 |
|
413 | if (nextPartialState) {
|
414 | appendMap(partialState, nextPartialState);
|
415 | }
|
416 | } else {
|
417 | addWriteThunk(function (prev) {
|
418 | var nextPartialState = updateAtomState(prev, a, v);
|
419 |
|
420 | if (nextPartialState) {
|
421 | return concatMap(prev, nextPartialState);
|
422 | }
|
423 |
|
424 | return prev;
|
425 | });
|
426 | }
|
427 | }
|
428 | }, update);
|
429 |
|
430 | if (promiseOrVoid instanceof Promise) {
|
431 | pendingPromises.push(promiseOrVoid);
|
432 |
|
433 | var nextAtomState = _extends({}, getAtomState(atom, prevState, partialState), {
|
434 | writeP: promiseOrVoid.then(function () {
|
435 | addWriteThunk(function (prev) {
|
436 | return new Map(prev).set(atom, _extends({}, getAtomState(atom, prev), {
|
437 | writeP: undefined
|
438 | }));
|
439 | });
|
440 | })
|
441 | });
|
442 |
|
443 | partialState.set(atom, nextAtomState);
|
444 | }
|
445 | } catch (e) {
|
446 | if (pendingPromises.length) {
|
447 | pendingPromises.push(new Promise(function (_resolve, reject) {
|
448 | reject(e);
|
449 | }));
|
450 | } else {
|
451 | throw e;
|
452 | }
|
453 | }
|
454 |
|
455 | isSync = false;
|
456 | return partialState;
|
457 | };
|
458 |
|
459 | addWriteThunk(function (prevState) {
|
460 | var nextPartialState = updateAtomState(prevState, updatingAtom, update);
|
461 |
|
462 | if (nextPartialState) {
|
463 | return concatMap(prevState, nextPartialState);
|
464 | }
|
465 |
|
466 | return prevState;
|
467 | });
|
468 |
|
469 | if (pendingPromises.length) {
|
470 | return new Promise(function (resolve, reject) {
|
471 | var loop = function loop() {
|
472 | var len = pendingPromises.length;
|
473 |
|
474 | if (len === 0) {
|
475 | resolve();
|
476 | } else {
|
477 | Promise.all(pendingPromises).then(function () {
|
478 | pendingPromises.splice(0, len);
|
479 | loop();
|
480 | }).catch(reject);
|
481 | }
|
482 | };
|
483 |
|
484 | loop();
|
485 | });
|
486 | }
|
487 | };
|
488 |
|
489 | var runWriteThunk = function runWriteThunk(lastStateRef, setState, writeThunkQueue) {
|
490 | while (true) {
|
491 | if (!lastStateRef.current) {
|
492 | return;
|
493 | }
|
494 |
|
495 | if (writeThunkQueue.length === 0) {
|
496 | return;
|
497 | }
|
498 |
|
499 | var thunk = writeThunkQueue.shift();
|
500 | var lastState = lastStateRef.current;
|
501 | var nextState = thunk(lastState);
|
502 |
|
503 | if (nextState !== lastState) {
|
504 | setState(nextState);
|
505 | return;
|
506 | }
|
507 | }
|
508 | };
|
509 |
|
510 | var ActionsContext = useContextSelector.createContext(warningObject);
|
511 | var StateContext = useContextSelector.createContext(warningObject);
|
512 | var Provider = function Provider(_ref) {
|
513 | var children = _ref.children;
|
514 | var dependentsMapRef = react.useRef();
|
515 |
|
516 | if (!dependentsMapRef.current) {
|
517 | dependentsMapRef.current = new Map();
|
518 | }
|
519 |
|
520 | var readPendingMapRef = react.useRef();
|
521 |
|
522 | if (!readPendingMapRef.current) {
|
523 | readPendingMapRef.current = new WeakMap();
|
524 | }
|
525 |
|
526 | var _useState = react.useState(initialState),
|
527 | state = _useState[0],
|
528 | setStateOrig = _useState[1];
|
529 |
|
530 | var lastStateRef = react.useRef(null);
|
531 |
|
532 | var setState = function setState(setStateAction) {
|
533 | lastStateRef.current = null;
|
534 | setStateOrig(setStateAction);
|
535 | };
|
536 |
|
537 | useIsoLayoutEffect(function () {
|
538 | if (state !== initialState) {
|
539 | lastStateRef.current = state;
|
540 | }
|
541 | });
|
542 |
|
543 | var _useState2 = react.useState(0),
|
544 | gcCount = _useState2[0],
|
545 | setGcCount = _useState2[1];
|
546 |
|
547 |
|
548 | react.useEffect(function () {
|
549 | gcAtom(state, setState, dependentsMapRef.current);
|
550 | }, [state, gcCount]);
|
551 | var writeThunkQueueRef = react.useRef([]);
|
552 | react.useEffect(function () {
|
553 | runWriteThunk(lastStateRef, setState, writeThunkQueueRef.current);
|
554 | }, [state]);
|
555 | var actions = react.useMemo(function () {
|
556 | return {
|
557 | add: function add(id, atom) {
|
558 | return addAtom(id, atom, setState, dependentsMapRef.current, readPendingMapRef.current);
|
559 | },
|
560 | del: function del(id) {
|
561 | return delAtom(id, setGcCount, dependentsMapRef.current);
|
562 | },
|
563 | read: function read(state, atom) {
|
564 | return readAtom(state, atom, setState, dependentsMapRef.current, readPendingMapRef.current);
|
565 | },
|
566 | write: function write(atom, update) {
|
567 | return writeAtom(atom, update, setState, dependentsMapRef.current, function (thunk) {
|
568 | writeThunkQueueRef.current.push(thunk);
|
569 | runWriteThunk(lastStateRef, setState, writeThunkQueueRef.current);
|
570 | });
|
571 | }
|
572 | };
|
573 | }, []);
|
574 | return react.createElement(ActionsContext.Provider, {
|
575 | value: actions
|
576 | }, react.createElement(StateContext.Provider, {
|
577 | value: state
|
578 | }, children));
|
579 | };
|
580 |
|
581 | var keyCount = 0;
|
582 |
|
583 | function atom(read, write) {
|
584 | var config = {
|
585 | key: ++keyCount
|
586 | };
|
587 |
|
588 | if (typeof read === 'function') {
|
589 | config.read = read;
|
590 | } else {
|
591 | config.init = read;
|
592 |
|
593 | config.read = function (get) {
|
594 | return get(config);
|
595 | };
|
596 |
|
597 | config.write = function (get, set, update) {
|
598 | set(config, typeof update === 'function' ? update(get(config)) : update);
|
599 | };
|
600 | }
|
601 |
|
602 | if (write) {
|
603 | config.write = write;
|
604 | }
|
605 |
|
606 | return config;
|
607 | }
|
608 |
|
609 | var isWritable = function isWritable(atom) {
|
610 | return !!atom.write;
|
611 | };
|
612 |
|
613 | function useAtom(atom) {
|
614 | var actions = useContextSelector.useContext(ActionsContext);
|
615 | var value = useContextSelector.useContextSelector(StateContext, react.useCallback(function (state) {
|
616 | var atomState = actions.read(state, atom);
|
617 |
|
618 | if (atomState.readE) {
|
619 | throw atomState.readE;
|
620 | }
|
621 |
|
622 | if (atomState.readP) {
|
623 | throw atomState.readP;
|
624 | }
|
625 |
|
626 | if (atomState.writeP) {
|
627 | throw atomState.writeP;
|
628 | }
|
629 |
|
630 | return atomState.value;
|
631 | }, [atom, actions]));
|
632 | useIsoLayoutEffect(function () {
|
633 | var id = Symbol();
|
634 | actions.add(id, atom);
|
635 | return function () {
|
636 | actions.del(id);
|
637 | };
|
638 | }, [actions, atom]);
|
639 | var setAtom = react.useCallback(function (update) {
|
640 | if (isWritable(atom)) {
|
641 | return actions.write(atom, update);
|
642 | } else {
|
643 | throw new Error('not writable atom');
|
644 | }
|
645 | }, [atom, actions]);
|
646 | react.useDebugValue(value);
|
647 | return [value, setAtom];
|
648 | }
|
649 |
|
650 | var useBridge = function useBridge() {
|
651 | var actions = useContextSelector.useContext(ActionsContext);
|
652 | var state = useContextSelector.useContext(StateContext);
|
653 | return react.useMemo(function () {
|
654 | return [actions, state];
|
655 | }, [actions, state]);
|
656 | };
|
657 | var Bridge = function Bridge(_ref) {
|
658 | var value = _ref.value,
|
659 | children = _ref.children;
|
660 | var actions = value[0],
|
661 | state = value[1];
|
662 | return react.createElement(useContextSelector.BridgeProvider, {
|
663 | context: ActionsContext,
|
664 | value: actions
|
665 | }, react.createElement(useContextSelector.BridgeProvider, {
|
666 | context: StateContext,
|
667 | value: state
|
668 | }, children));
|
669 | };
|
670 |
|
671 | exports.Bridge = Bridge;
|
672 | exports.Provider = Provider;
|
673 | exports.atom = atom;
|
674 | exports.useAtom = useAtom;
|
675 | exports.useBridge = useBridge;
|