UNPKG

23.3 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(config);
21 };
22 config.write = function (get, set, arg) {
23 return set(config, typeof arg === 'function' ? arg(get(config)) : 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 'v' in a && 'v' in b && Object.is(a.v, b.v);
97 };
98 var isEqualAtomError = function isEqualAtomError(a, b) {
99 return 'e' in a && 'e' in b && Object.is(a.e, b.e);
100 };
101 var hasPromiseAtomValue = function hasPromiseAtomValue(a) {
102 return '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 (prevAtomState && hasPromiseAtomValue(prevAtomState)) {
136 var _next = 'v' in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
137 cancelPromise(prevAtomState.v, _next);
138 }
139 };
140 var updateDependencies = function updateDependencies(atom, nextAtomState, nextDependencies) {
141 var dependencies = new Map();
142 var changed = false;
143 nextDependencies.forEach(function (aState, a) {
144 if (!aState && a === atom) {
145 aState = nextAtomState;
146 }
147 if (aState) {
148 dependencies.set(a, aState);
149 if (nextAtomState.d.get(a) !== aState) {
150 changed = true;
151 }
152 } else {
153 console.warn('[Bug] atom state not found');
154 }
155 });
156 if (changed || nextAtomState.d.size !== dependencies.size) {
157 nextAtomState.d = dependencies;
158 }
159 };
160 var setAtomValue = function setAtomValue(atom, value, nextDependencies) {
161 var prevAtomState = getAtomState(atom);
162 var nextAtomState = {
163 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
164 v: value
165 };
166 if (nextDependencies) {
167 updateDependencies(atom, nextAtomState, nextDependencies);
168 }
169 if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
170 return prevAtomState;
171 }
172 if (prevAtomState && hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) {
173 if (prevAtomState.d === nextAtomState.d) {
174 return prevAtomState;
175 } else {
176 nextAtomState.v = prevAtomState.v;
177 }
178 }
179 setAtomState(atom, nextAtomState);
180 return nextAtomState;
181 };
182 var setAtomValueOrPromise = function setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, abortPromise) {
183 if (isPromiseLike(valueOrPromise)) {
184 var continuePromise;
185 var promise = new Promise(function (resolve, reject) {
186 var settled = false;
187 valueOrPromise.then(function (v) {
188 if (!settled) {
189 settled = true;
190 var prevAtomState = getAtomState(atom);
191 var nextAtomState = setAtomValue(atom, promise, nextDependencies);
192 resolvePromise(promise, v);
193 resolve(v);
194 if (mountedMap.has(atom) && (prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) {
195 mountDependencies(atom, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d);
196 }
197 }
198 }, function (e) {
199 if (!settled) {
200 settled = true;
201 var prevAtomState = getAtomState(atom);
202 var nextAtomState = setAtomValue(atom, promise, nextDependencies);
203 rejectPromise(promise, e);
204 reject(e);
205 if (mountedMap.has(atom) && (prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) {
206 mountDependencies(atom, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d);
207 }
208 }
209 });
210 continuePromise = function continuePromise(next) {
211 if (!settled) {
212 settled = true;
213 next.then(function (v) {
214 return resolvePromise(promise, v);
215 }, function (e) {
216 return rejectPromise(promise, e);
217 });
218 resolve(next);
219 }
220 };
221 });
222 promise.orig = valueOrPromise;
223 promise.status = 'pending';
224 registerCancelPromise(promise, function (next) {
225 if (next) {
226 continuePromise(next);
227 }
228 abortPromise == null || abortPromise();
229 });
230 return setAtomValue(atom, promise, nextDependencies);
231 }
232 return setAtomValue(atom, valueOrPromise, nextDependencies);
233 };
234 var setAtomError = function setAtomError(atom, error, nextDependencies) {
235 var prevAtomState = getAtomState(atom);
236 var nextAtomState = {
237 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
238 e: error
239 };
240 if (nextDependencies) {
241 updateDependencies(atom, nextAtomState, nextDependencies);
242 }
243 if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
244 return prevAtomState;
245 }
246 setAtomState(atom, nextAtomState);
247 return nextAtomState;
248 };
249 var readAtomState = function readAtomState(atom, force) {
250 var atomState = getAtomState(atom);
251 if (!force && atomState) {
252 if (mountedMap.has(atom)) {
253 return atomState;
254 }
255 if (Array.from(atomState.d).every(function (_ref) {
256 var a = _ref[0],
257 s = _ref[1];
258 return a === atom || readAtomState(a) === s;
259 })) {
260 return atomState;
261 }
262 }
263 var nextDependencies = new Map();
264 var isSync = true;
265 var getter = function getter(a) {
266 if (a === atom) {
267 var _aState = getAtomState(a);
268 if (_aState) {
269 nextDependencies.set(a, _aState);
270 return returnAtomValue(_aState);
271 }
272 if (hasInitialValue(a)) {
273 nextDependencies.set(a, undefined);
274 return a.init;
275 }
276 throw new Error('no atom init');
277 }
278 var aState = readAtomState(a);
279 nextDependencies.set(a, aState);
280 return returnAtomValue(aState);
281 };
282 var controller;
283 var setSelf;
284 var options = {
285 get signal() {
286 if (!controller) {
287 controller = new AbortController();
288 }
289 return controller.signal;
290 },
291 get setSelf() {
292 if (!isActuallyWritableAtom(atom)) {
293 console.warn('setSelf function cannot be used with read-only atom');
294 }
295 if (!setSelf && isActuallyWritableAtom(atom)) {
296 setSelf = function setSelf() {
297 if (isSync) {
298 console.warn('setSelf function cannot be called in sync');
299 }
300 if (!isSync) {
301 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
302 args[_key] = arguments[_key];
303 }
304 return writeAtom.apply(void 0, [atom].concat(args));
305 }
306 };
307 }
308 return setSelf;
309 }
310 };
311 try {
312 var valueOrPromise = atom.read(getter, options);
313 return setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, function () {
314 var _controller;
315 return (_controller = controller) == null ? void 0 : _controller.abort();
316 });
317 } catch (error) {
318 return setAtomError(atom, error, nextDependencies);
319 } finally {
320 isSync = false;
321 }
322 };
323 var readAtom = function readAtom(atom) {
324 return returnAtomValue(readAtomState(atom));
325 };
326 var addAtom = function addAtom(atom) {
327 var mounted = mountedMap.get(atom);
328 if (!mounted) {
329 mounted = mountAtom(atom);
330 }
331 return mounted;
332 };
333 var canUnmountAtom = function canUnmountAtom(atom, mounted) {
334 return !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
335 };
336 var delAtom = function delAtom(atom) {
337 var mounted = mountedMap.get(atom);
338 if (mounted && canUnmountAtom(atom, mounted)) {
339 unmountAtom(atom);
340 }
341 };
342 var recomputeDependents = function recomputeDependents(updatedAtoms) {
343 if (!updatedAtoms.size) {
344 return;
345 }
346 var dependencyMap = new Map();
347 var dirtyMap = new WeakMap();
348 var loop1 = function loop1(a) {
349 var mounted = mountedMap.get(a);
350 mounted == null || mounted.t.forEach(function (dependent) {
351 if (dependent !== a) {
352 dependencyMap.set(dependent, (dependencyMap.get(dependent) || new Set()).add(a));
353 dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1);
354 loop1(dependent);
355 }
356 });
357 };
358 updatedAtoms.forEach(loop1);
359 var loop2 = function loop2(a) {
360 var mounted = mountedMap.get(a);
361 mounted == null || mounted.t.forEach(function (dependent) {
362 if (dependent !== a) {
363 var dirtyCount = dirtyMap.get(dependent);
364 if (dirtyCount) {
365 dirtyMap.set(dependent, --dirtyCount);
366 }
367 if (!dirtyCount) {
368 var _dependencyMap$get;
369 var isChanged = !!((_dependencyMap$get = dependencyMap.get(dependent)) != null && _dependencyMap$get.size);
370 if (isChanged) {
371 var prevAtomState = getAtomState(dependent);
372 var nextAtomState = readAtomState(dependent, true);
373 isChanged = !prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState);
374 }
375 if (!isChanged) {
376 dependencyMap.forEach(function (s) {
377 return s.delete(dependent);
378 });
379 }
380 }
381 loop2(dependent);
382 }
383 });
384 };
385 updatedAtoms.forEach(loop2);
386 updatedAtoms.clear();
387 };
388 var writeAtomState = function writeAtomState(updatedAtoms, atom) {
389 var isSync = true;
390 var getter = function getter(a) {
391 return returnAtomValue(readAtomState(a));
392 };
393 var setter = function setter(a) {
394 var r;
395 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
396 args[_key3 - 1] = arguments[_key3];
397 }
398 if (a === atom) {
399 if (!hasInitialValue(a)) {
400 throw new Error('atom not writable');
401 }
402 var prevAtomState = getAtomState(a);
403 var nextAtomState = setAtomValueOrPromise(a, args[0]);
404 if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
405 updatedAtoms.add(a);
406 }
407 } else {
408 r = writeAtomState.apply(void 0, [updatedAtoms, a].concat(args));
409 }
410 if (!isSync) {
411 recomputeDependents(updatedAtoms);
412 var flushed = flushPending();
413 {
414 storeListenersRev2.forEach(function (l) {
415 return l({
416 type: 'async-write',
417 flushed: flushed
418 });
419 });
420 }
421 }
422 return r;
423 };
424 for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
425 args[_key2 - 2] = arguments[_key2];
426 }
427 var result = atom.write.apply(atom, [getter, setter].concat(args));
428 isSync = false;
429 return result;
430 };
431 var writeAtom = function writeAtom(atom) {
432 var updatedAtoms = new Set();
433 for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
434 args[_key4 - 1] = arguments[_key4];
435 }
436 var result = writeAtomState.apply(void 0, [updatedAtoms, atom].concat(args));
437 recomputeDependents(updatedAtoms);
438 var flushed = flushPending();
439 {
440 storeListenersRev2.forEach(function (l) {
441 return l({
442 type: 'write',
443 flushed: flushed
444 });
445 });
446 }
447 return result;
448 };
449 var mountAtom = function mountAtom(atom, initialDependent, onMountQueue) {
450 var _getAtomState;
451 var queue = onMountQueue || [];
452 (_getAtomState = getAtomState(atom)) == null || _getAtomState.d.forEach(function (_, a) {
453 var aMounted = mountedMap.get(a);
454 if (aMounted) {
455 aMounted.t.add(atom);
456 } else {
457 if (a !== atom) {
458 mountAtom(a, atom, queue);
459 }
460 }
461 });
462 readAtomState(atom);
463 var mounted = {
464 t: new Set(initialDependent && [initialDependent]),
465 l: new Set()
466 };
467 mountedMap.set(atom, mounted);
468 {
469 mountedAtoms.add(atom);
470 }
471 if (isActuallyWritableAtom(atom) && atom.onMount) {
472 var onMount = atom.onMount;
473 queue.push(function () {
474 var onUnmount = onMount(function () {
475 for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
476 args[_key5] = arguments[_key5];
477 }
478 return writeAtom.apply(void 0, [atom].concat(args));
479 });
480 if (onUnmount) {
481 mounted.u = onUnmount;
482 }
483 });
484 }
485 if (!onMountQueue) {
486 queue.forEach(function (f) {
487 return f();
488 });
489 }
490 return mounted;
491 };
492 var unmountAtom = function unmountAtom(atom) {
493 var _mountedMap$get;
494 var onUnmount = (_mountedMap$get = mountedMap.get(atom)) == null ? void 0 : _mountedMap$get.u;
495 if (onUnmount) {
496 onUnmount();
497 }
498 mountedMap.delete(atom);
499 {
500 mountedAtoms.delete(atom);
501 }
502 var atomState = getAtomState(atom);
503 if (atomState) {
504 if (hasPromiseAtomValue(atomState)) {
505 cancelPromise(atomState.v);
506 }
507 atomState.d.forEach(function (_, a) {
508 if (a !== atom) {
509 var mounted = mountedMap.get(a);
510 if (mounted) {
511 mounted.t.delete(atom);
512 if (canUnmountAtom(a, mounted)) {
513 unmountAtom(a);
514 }
515 }
516 }
517 });
518 } else {
519 console.warn('[Bug] could not find atom state to unmount', atom);
520 }
521 };
522 var mountDependencies = function mountDependencies(atom, atomState, prevDependencies) {
523 var depSet = new Set(atomState.d.keys());
524 prevDependencies == null || prevDependencies.forEach(function (_, a) {
525 if (depSet.has(a)) {
526 depSet.delete(a);
527 return;
528 }
529 var mounted = mountedMap.get(a);
530 if (mounted) {
531 mounted.t.delete(atom);
532 if (canUnmountAtom(a, mounted)) {
533 unmountAtom(a);
534 }
535 }
536 });
537 depSet.forEach(function (a) {
538 var mounted = mountedMap.get(a);
539 if (mounted) {
540 mounted.t.add(atom);
541 } else if (mountedMap.has(atom)) {
542 mountAtom(a, atom);
543 }
544 });
545 };
546 var flushPending = function flushPending() {
547 var flushed;
548 {
549 flushed = new Set();
550 }
551 while (pendingMap.size) {
552 var pending = Array.from(pendingMap);
553 pendingMap.clear();
554 pending.forEach(function (_ref2) {
555 var atom = _ref2[0],
556 prevAtomState = _ref2[1];
557 var atomState = getAtomState(atom);
558 if (atomState) {
559 var mounted = mountedMap.get(atom);
560 if (mounted && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
561 mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
562 }
563 if (mounted && !(prevAtomState && !hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
564 mounted.l.forEach(function (listener) {
565 return listener();
566 });
567 {
568 flushed.add(atom);
569 }
570 }
571 } else {
572 console.warn('[Bug] no atom state to flush');
573 }
574 });
575 }
576 {
577 return flushed;
578 }
579 };
580 var subscribeAtom = function subscribeAtom(atom, listener) {
581 var mounted = addAtom(atom);
582 var flushed = flushPending();
583 var listeners = mounted.l;
584 listeners.add(listener);
585 {
586 storeListenersRev2.forEach(function (l) {
587 return l({
588 type: 'sub',
589 flushed: flushed
590 });
591 });
592 }
593 return function () {
594 listeners.delete(listener);
595 delAtom(atom);
596 {
597 storeListenersRev2.forEach(function (l) {
598 return l({
599 type: 'unsub'
600 });
601 });
602 }
603 };
604 };
605 {
606 return {
607 get: readAtom,
608 set: writeAtom,
609 sub: subscribeAtom,
610 dev_subscribe_store: function dev_subscribe_store(l, rev) {
611 if (rev !== 2) {
612 throw new Error('The current StoreListener revision is 2.');
613 }
614 storeListenersRev2.add(l);
615 return function () {
616 storeListenersRev2.delete(l);
617 };
618 },
619 dev_get_mounted_atoms: function dev_get_mounted_atoms() {
620 return mountedAtoms.values();
621 },
622 dev_get_atom_state: function dev_get_atom_state(a) {
623 return atomStateMap.get(a);
624 },
625 dev_get_mounted: function dev_get_mounted(a) {
626 return mountedMap.get(a);
627 },
628 dev_restore_atoms: function dev_restore_atoms(values) {
629 var updatedAtoms = new Set();
630 for (var _iterator = _createForOfIteratorHelperLoose(values), _step; !(_step = _iterator()).done;) {
631 var _step$value = _step.value,
632 atom = _step$value[0],
633 valueOrPromise = _step$value[1];
634 if (hasInitialValue(atom)) {
635 setAtomValueOrPromise(atom, valueOrPromise);
636 updatedAtoms.add(atom);
637 }
638 }
639 recomputeDependents(updatedAtoms);
640 var flushed = flushPending();
641 storeListenersRev2.forEach(function (l) {
642 return l({
643 type: 'restore',
644 flushed: flushed
645 });
646 });
647 }
648 };
649 }
650 };
651 var defaultStore;
652 {
653 if (typeof globalThis.__NUMBER_OF_JOTAI_INSTANCES__ === 'number') {
654 ++globalThis.__NUMBER_OF_JOTAI_INSTANCES__;
655 } else {
656 globalThis.__NUMBER_OF_JOTAI_INSTANCES__ = 1;
657 }
658 }
659 var getDefaultStore = function getDefaultStore() {
660 if (!defaultStore) {
661 if (globalThis.__NUMBER_OF_JOTAI_INSTANCES__ !== 1) {
662 console.warn('Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044');
663 }
664 defaultStore = createStore();
665 }
666 return defaultStore;
667 };
668
669 exports.atom = atom;
670 exports.createStore = createStore;
671 exports.getDefaultStore = getDefaultStore;
672
673}));