UNPKG

23.2 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jotaiVanilla = {}));
5})(this, (function (exports) { 'use strict';
6
7 var keyCount = 0;
8 function atom(read, write) {
9 var key = "atom" + ++keyCount;
10 var config = {
11 toString: function toString() {
12 return key;
13 }
14 };
15 if (typeof read === 'function') {
16 config.read = read;
17 } else {
18 config.init = read;
19 config.read = function (get) {
20 return get(this);
21 };
22 config.write = function (get, set, arg) {
23 return set(this, typeof arg === 'function' ? arg(get(this)) : arg);
24 };
25 }
26 if (write) {
27 config.write = write;
28 }
29 return config;
30 }
31
32 function _unsupportedIterableToArray(o, minLen) {
33 if (!o) return;
34 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
35 var n = Object.prototype.toString.call(o).slice(8, -1);
36 if (n === "Object" && o.constructor) n = o.constructor.name;
37 if (n === "Map" || n === "Set") return Array.from(o);
38 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
39 }
40 function _arrayLikeToArray(arr, len) {
41 if (len == null || len > arr.length) len = arr.length;
42 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
43 return arr2;
44 }
45 function _createForOfIteratorHelperLoose(o, allowArrayLike) {
46 var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
47 if (it) return (it = it.call(o)).next.bind(it);
48 if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
49 if (it) o = it;
50 var i = 0;
51 return function () {
52 if (i >= o.length) return {
53 done: true
54 };
55 return {
56 done: false,
57 value: o[i++]
58 };
59 };
60 }
61 throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
62 }
63
64 var hasInitialValue = function hasInitialValue(atom) {
65 return 'init' in atom;
66 };
67 var isActuallyWritableAtom = function isActuallyWritableAtom(atom) {
68 return !!atom.write;
69 };
70 var cancelPromiseMap = new WeakMap();
71 var registerCancelPromise = function registerCancelPromise(promise, cancel) {
72 cancelPromiseMap.set(promise, cancel);
73 promise.catch(function () {}).finally(function () {
74 return cancelPromiseMap.delete(promise);
75 });
76 };
77 var cancelPromise = function cancelPromise(promise, next) {
78 var cancel = cancelPromiseMap.get(promise);
79 if (cancel) {
80 cancelPromiseMap.delete(promise);
81 cancel(next);
82 }
83 };
84 var resolvePromise = function resolvePromise(promise, value) {
85 promise.status = 'fulfilled';
86 promise.value = value;
87 };
88 var rejectPromise = function rejectPromise(promise, e) {
89 promise.status = 'rejected';
90 promise.reason = e;
91 };
92 var isPromiseLike = function isPromiseLike(x) {
93 return typeof (x == null ? void 0 : x.then) === 'function';
94 };
95 var isEqualAtomValue = function isEqualAtomValue(a, b) {
96 return !!a && 'v' in a && 'v' in b && Object.is(a.v, b.v);
97 };
98 var isEqualAtomError = function isEqualAtomError(a, b) {
99 return !!a && 'e' in a && 'e' in b && Object.is(a.e, b.e);
100 };
101 var hasPromiseAtomValue = function hasPromiseAtomValue(a) {
102 return !!a && 'v' in a && a.v instanceof Promise;
103 };
104 var isEqualPromiseAtomValue = function isEqualPromiseAtomValue(a, b) {
105 return 'v' in a && 'v' in b && a.v.orig && a.v.orig === b.v.orig;
106 };
107 var returnAtomValue = function returnAtomValue(atomState) {
108 if ('e' in atomState) {
109 throw atomState.e;
110 }
111 return atomState.v;
112 };
113 var createStore = function createStore() {
114 var atomStateMap = new WeakMap();
115 var mountedMap = new WeakMap();
116 var pendingMap = new Map();
117 var storeListenersRev2;
118 var mountedAtoms;
119 {
120 storeListenersRev2 = new Set();
121 mountedAtoms = new Set();
122 }
123 var getAtomState = function getAtomState(atom) {
124 return atomStateMap.get(atom);
125 };
126 var setAtomState = function setAtomState(atom, atomState) {
127 {
128 Object.freeze(atomState);
129 }
130 var prevAtomState = atomStateMap.get(atom);
131 atomStateMap.set(atom, atomState);
132 if (!pendingMap.has(atom)) {
133 pendingMap.set(atom, prevAtomState);
134 }
135 if (hasPromiseAtomValue(prevAtomState)) {
136 var _next = 'v' in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
137 if (prevAtomState.v !== _next) {
138 cancelPromise(prevAtomState.v, _next);
139 }
140 }
141 };
142 var updateDependencies = function updateDependencies(atom, nextAtomState, nextDependencies) {
143 var dependencies = new Map();
144 var changed = false;
145 nextDependencies.forEach(function (aState, a) {
146 if (!aState && a === atom) {
147 aState = nextAtomState;
148 }
149 if (aState) {
150 dependencies.set(a, aState);
151 if (nextAtomState.d.get(a) !== aState) {
152 changed = true;
153 }
154 } else {
155 console.warn('[Bug] atom state not found');
156 }
157 });
158 if (changed || nextAtomState.d.size !== dependencies.size) {
159 nextAtomState.d = dependencies;
160 }
161 };
162 var setAtomValue = function setAtomValue(atom, value, nextDependencies) {
163 var prevAtomState = getAtomState(atom);
164 var nextAtomState = {
165 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
166 v: value
167 };
168 if (nextDependencies) {
169 updateDependencies(atom, nextAtomState, nextDependencies);
170 }
171 if (isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
172 return prevAtomState;
173 }
174 if (hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) {
175 if (prevAtomState.d === nextAtomState.d) {
176 return prevAtomState;
177 } else {
178 nextAtomState.v = prevAtomState.v;
179 }
180 }
181 setAtomState(atom, nextAtomState);
182 return nextAtomState;
183 };
184 var setAtomValueOrPromise = function setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, abortPromise) {
185 if (isPromiseLike(valueOrPromise)) {
186 var continuePromise;
187 var updatePromiseDependencies = function updatePromiseDependencies() {
188 var prevAtomState = getAtomState(atom);
189 if (!hasPromiseAtomValue(prevAtomState) || prevAtomState.v !== promise) {
190 return;
191 }
192 var nextAtomState = setAtomValue(atom, promise, nextDependencies);
193 if (mountedMap.has(atom) && prevAtomState.d !== nextAtomState.d) {
194 mountDependencies(atom, nextAtomState, prevAtomState.d);
195 }
196 };
197 var promise = new Promise(function (resolve, reject) {
198 var settled = false;
199 valueOrPromise.then(function (v) {
200 if (!settled) {
201 settled = true;
202 resolvePromise(promise, v);
203 resolve(v);
204 updatePromiseDependencies();
205 }
206 }, function (e) {
207 if (!settled) {
208 settled = true;
209 rejectPromise(promise, e);
210 reject(e);
211 updatePromiseDependencies();
212 }
213 });
214 continuePromise = function continuePromise(next) {
215 if (!settled) {
216 settled = true;
217 next.then(function (v) {
218 return resolvePromise(promise, v);
219 }, function (e) {
220 return rejectPromise(promise, e);
221 });
222 resolve(next);
223 }
224 };
225 });
226 promise.orig = valueOrPromise;
227 promise.status = 'pending';
228 registerCancelPromise(promise, function (next) {
229 if (next) {
230 continuePromise(next);
231 }
232 abortPromise == null || abortPromise();
233 });
234 return setAtomValue(atom, promise, nextDependencies);
235 }
236 return setAtomValue(atom, valueOrPromise, nextDependencies);
237 };
238 var setAtomError = function setAtomError(atom, error, nextDependencies) {
239 var prevAtomState = getAtomState(atom);
240 var nextAtomState = {
241 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
242 e: error
243 };
244 if (nextDependencies) {
245 updateDependencies(atom, nextAtomState, nextDependencies);
246 }
247 if (isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
248 return prevAtomState;
249 }
250 setAtomState(atom, nextAtomState);
251 return nextAtomState;
252 };
253 var readAtomState = function readAtomState(atom, force) {
254 var atomState = getAtomState(atom);
255 if (!force && atomState) {
256 if (mountedMap.has(atom)) {
257 return atomState;
258 }
259 if (Array.from(atomState.d).every(function (_ref) {
260 var a = _ref[0],
261 s = _ref[1];
262 if (a === atom) {
263 return true;
264 }
265 var aState = readAtomState(a);
266 return aState === s || isEqualAtomValue(aState, s);
267 })) {
268 return atomState;
269 }
270 }
271 var nextDependencies = new Map();
272 var isSync = true;
273 var getter = function getter(a) {
274 if (a === atom) {
275 var _aState = getAtomState(a);
276 if (_aState) {
277 nextDependencies.set(a, _aState);
278 return returnAtomValue(_aState);
279 }
280 if (hasInitialValue(a)) {
281 nextDependencies.set(a, undefined);
282 return a.init;
283 }
284 throw new Error('no atom init');
285 }
286 var aState = readAtomState(a);
287 nextDependencies.set(a, aState);
288 return returnAtomValue(aState);
289 };
290 var controller;
291 var setSelf;
292 var options = {
293 get signal() {
294 if (!controller) {
295 controller = new AbortController();
296 }
297 return controller.signal;
298 },
299 get setSelf() {
300 if (!isActuallyWritableAtom(atom)) {
301 console.warn('setSelf function cannot be used with read-only atom');
302 }
303 if (!setSelf && isActuallyWritableAtom(atom)) {
304 setSelf = function setSelf() {
305 if (isSync) {
306 console.warn('setSelf function cannot be called in sync');
307 }
308 if (!isSync) {
309 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
310 args[_key] = arguments[_key];
311 }
312 return writeAtom.apply(void 0, [atom].concat(args));
313 }
314 };
315 }
316 return setSelf;
317 }
318 };
319 try {
320 var valueOrPromise = atom.read(getter, options);
321 return setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, function () {
322 var _controller;
323 return (_controller = controller) == null ? void 0 : _controller.abort();
324 });
325 } catch (error) {
326 return setAtomError(atom, error, nextDependencies);
327 } finally {
328 isSync = false;
329 }
330 };
331 var readAtom = function readAtom(atom) {
332 return returnAtomValue(readAtomState(atom));
333 };
334 var addAtom = function addAtom(atom) {
335 var mounted = mountedMap.get(atom);
336 if (!mounted) {
337 mounted = mountAtom(atom);
338 }
339 return mounted;
340 };
341 var canUnmountAtom = function canUnmountAtom(atom, mounted) {
342 return !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
343 };
344 var delAtom = function delAtom(atom) {
345 var mounted = mountedMap.get(atom);
346 if (mounted && canUnmountAtom(atom, mounted)) {
347 unmountAtom(atom);
348 }
349 };
350 var recomputeDependents = function recomputeDependents(atom) {
351 var dependencyMap = new Map();
352 var dirtyMap = new WeakMap();
353 var getDependents = function getDependents(a) {
354 var _mountedMap$get;
355 var dependents = new Set((_mountedMap$get = mountedMap.get(a)) == null ? void 0 : _mountedMap$get.t);
356 pendingMap.forEach(function (_, pendingAtom) {
357 var _getAtomState;
358 if ((_getAtomState = getAtomState(pendingAtom)) != null && _getAtomState.d.has(a)) {
359 dependents.add(pendingAtom);
360 }
361 });
362 return dependents;
363 };
364 var loop1 = function loop1(a) {
365 getDependents(a).forEach(function (dependent) {
366 if (dependent !== a) {
367 dependencyMap.set(dependent, (dependencyMap.get(dependent) || new Set()).add(a));
368 dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1);
369 loop1(dependent);
370 }
371 });
372 };
373 loop1(atom);
374 var loop2 = function loop2(a) {
375 getDependents(a).forEach(function (dependent) {
376 if (dependent !== a) {
377 var dirtyCount = dirtyMap.get(dependent);
378 if (dirtyCount) {
379 dirtyMap.set(dependent, --dirtyCount);
380 }
381 if (!dirtyCount) {
382 var _dependencyMap$get;
383 var isChanged = !!((_dependencyMap$get = dependencyMap.get(dependent)) != null && _dependencyMap$get.size);
384 if (isChanged) {
385 var prevAtomState = getAtomState(dependent);
386 var nextAtomState = readAtomState(dependent, true);
387 isChanged = !isEqualAtomValue(prevAtomState, nextAtomState);
388 }
389 if (!isChanged) {
390 dependencyMap.forEach(function (s) {
391 return s.delete(dependent);
392 });
393 }
394 }
395 loop2(dependent);
396 }
397 });
398 };
399 loop2(atom);
400 };
401 var writeAtomState = function writeAtomState(atom) {
402 var isSync = true;
403 var getter = function getter(a) {
404 return returnAtomValue(readAtomState(a));
405 };
406 var setter = function setter(a) {
407 var r;
408 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
409 args[_key3 - 1] = arguments[_key3];
410 }
411 if (a === atom) {
412 if (!hasInitialValue(a)) {
413 throw new Error('atom not writable');
414 }
415 var prevAtomState = getAtomState(a);
416 var nextAtomState = setAtomValueOrPromise(a, args[0]);
417 if (!isEqualAtomValue(prevAtomState, nextAtomState)) {
418 recomputeDependents(a);
419 }
420 } else {
421 r = writeAtomState.apply(void 0, [a].concat(args));
422 }
423 if (!isSync) {
424 var flushed = flushPending();
425 {
426 storeListenersRev2.forEach(function (l) {
427 return l({
428 type: 'async-write',
429 flushed: flushed
430 });
431 });
432 }
433 }
434 return r;
435 };
436 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
437 args[_key2 - 1] = arguments[_key2];
438 }
439 var result = atom.write.apply(atom, [getter, setter].concat(args));
440 isSync = false;
441 return result;
442 };
443 var writeAtom = function writeAtom(atom) {
444 for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
445 args[_key4 - 1] = arguments[_key4];
446 }
447 var result = writeAtomState.apply(void 0, [atom].concat(args));
448 var flushed = flushPending();
449 {
450 storeListenersRev2.forEach(function (l) {
451 return l({
452 type: 'write',
453 flushed: flushed
454 });
455 });
456 }
457 return result;
458 };
459 var mountAtom = function mountAtom(atom, initialDependent, onMountQueue) {
460 var _getAtomState2;
461 var queue = onMountQueue || [];
462 (_getAtomState2 = getAtomState(atom)) == null || _getAtomState2.d.forEach(function (_, a) {
463 var aMounted = mountedMap.get(a);
464 if (aMounted) {
465 aMounted.t.add(atom);
466 } else {
467 if (a !== atom) {
468 mountAtom(a, atom, queue);
469 }
470 }
471 });
472 readAtomState(atom);
473 var mounted = {
474 t: new Set(initialDependent && [initialDependent]),
475 l: new Set()
476 };
477 mountedMap.set(atom, mounted);
478 {
479 mountedAtoms.add(atom);
480 }
481 if (isActuallyWritableAtom(atom) && atom.onMount) {
482 var onMount = atom.onMount;
483 queue.push(function () {
484 var onUnmount = onMount(function () {
485 for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
486 args[_key5] = arguments[_key5];
487 }
488 return writeAtom.apply(void 0, [atom].concat(args));
489 });
490 if (onUnmount) {
491 mounted.u = onUnmount;
492 }
493 });
494 }
495 if (!onMountQueue) {
496 queue.forEach(function (f) {
497 return f();
498 });
499 }
500 return mounted;
501 };
502 var unmountAtom = function unmountAtom(atom) {
503 var _mountedMap$get2;
504 var onUnmount = (_mountedMap$get2 = mountedMap.get(atom)) == null ? void 0 : _mountedMap$get2.u;
505 if (onUnmount) {
506 onUnmount();
507 }
508 mountedMap.delete(atom);
509 {
510 mountedAtoms.delete(atom);
511 }
512 var atomState = getAtomState(atom);
513 if (atomState) {
514 if (hasPromiseAtomValue(atomState)) {
515 cancelPromise(atomState.v);
516 }
517 atomState.d.forEach(function (_, a) {
518 if (a !== atom) {
519 var mounted = mountedMap.get(a);
520 if (mounted) {
521 mounted.t.delete(atom);
522 if (canUnmountAtom(a, mounted)) {
523 unmountAtom(a);
524 }
525 }
526 }
527 });
528 } else {
529 console.warn('[Bug] could not find atom state to unmount', atom);
530 }
531 };
532 var mountDependencies = function mountDependencies(atom, atomState, prevDependencies) {
533 var depSet = new Set(atomState.d.keys());
534 prevDependencies == null || prevDependencies.forEach(function (_, a) {
535 if (depSet.has(a)) {
536 depSet.delete(a);
537 return;
538 }
539 var mounted = mountedMap.get(a);
540 if (mounted) {
541 mounted.t.delete(atom);
542 if (canUnmountAtom(a, mounted)) {
543 unmountAtom(a);
544 }
545 }
546 });
547 depSet.forEach(function (a) {
548 var mounted = mountedMap.get(a);
549 if (mounted) {
550 mounted.t.add(atom);
551 } else if (mountedMap.has(atom)) {
552 mountAtom(a, atom);
553 }
554 });
555 };
556 var flushPending = function flushPending() {
557 var flushed;
558 {
559 flushed = new Set();
560 }
561 while (pendingMap.size) {
562 var pending = Array.from(pendingMap);
563 pendingMap.clear();
564 pending.forEach(function (_ref2) {
565 var atom = _ref2[0],
566 prevAtomState = _ref2[1];
567 var atomState = getAtomState(atom);
568 if (atomState) {
569 var mounted = mountedMap.get(atom);
570 if (mounted && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
571 mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
572 }
573 if (mounted && !(!hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
574 mounted.l.forEach(function (listener) {
575 return listener();
576 });
577 {
578 flushed.add(atom);
579 }
580 }
581 } else {
582 console.warn('[Bug] no atom state to flush');
583 }
584 });
585 }
586 {
587 return flushed;
588 }
589 };
590 var subscribeAtom = function subscribeAtom(atom, listener) {
591 var mounted = addAtom(atom);
592 var flushed = flushPending();
593 var listeners = mounted.l;
594 listeners.add(listener);
595 {
596 storeListenersRev2.forEach(function (l) {
597 return l({
598 type: 'sub',
599 flushed: flushed
600 });
601 });
602 }
603 return function () {
604 listeners.delete(listener);
605 delAtom(atom);
606 {
607 storeListenersRev2.forEach(function (l) {
608 return l({
609 type: 'unsub'
610 });
611 });
612 }
613 };
614 };
615 {
616 return {
617 get: readAtom,
618 set: writeAtom,
619 sub: subscribeAtom,
620 dev_subscribe_store: function dev_subscribe_store(l, rev) {
621 if (rev !== 2) {
622 throw new Error('The current StoreListener revision is 2.');
623 }
624 storeListenersRev2.add(l);
625 return function () {
626 storeListenersRev2.delete(l);
627 };
628 },
629 dev_get_mounted_atoms: function dev_get_mounted_atoms() {
630 return mountedAtoms.values();
631 },
632 dev_get_atom_state: function dev_get_atom_state(a) {
633 return atomStateMap.get(a);
634 },
635 dev_get_mounted: function dev_get_mounted(a) {
636 return mountedMap.get(a);
637 },
638 dev_restore_atoms: function dev_restore_atoms(values) {
639 for (var _iterator = _createForOfIteratorHelperLoose(values), _step; !(_step = _iterator()).done;) {
640 var _step$value = _step.value,
641 atom = _step$value[0],
642 valueOrPromise = _step$value[1];
643 if (hasInitialValue(atom)) {
644 setAtomValueOrPromise(atom, valueOrPromise);
645 recomputeDependents(atom);
646 }
647 }
648 var flushed = flushPending();
649 storeListenersRev2.forEach(function (l) {
650 return l({
651 type: 'restore',
652 flushed: flushed
653 });
654 });
655 }
656 };
657 }
658 };
659 var defaultStore;
660 {
661 if (typeof globalThis.__NUMBER_OF_JOTAI_INSTANCES__ === 'number') {
662 ++globalThis.__NUMBER_OF_JOTAI_INSTANCES__;
663 } else {
664 globalThis.__NUMBER_OF_JOTAI_INSTANCES__ = 1;
665 }
666 }
667 var getDefaultStore = function getDefaultStore() {
668 if (!defaultStore) {
669 if (globalThis.__NUMBER_OF_JOTAI_INSTANCES__ !== 1) {
670 console.warn('Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044');
671 }
672 defaultStore = createStore();
673 }
674 return defaultStore;
675 };
676
677 exports.atom = atom;
678 exports.createStore = createStore;
679 exports.getDefaultStore = getDefaultStore;
680
681}));