UNPKG

18.5 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.jotaiExperimental = {}));
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 = defaultRead;
20 config.write = defaultWrite;
21 }
22 if (write) {
23 config.write = write;
24 }
25 return config;
26 }
27 function defaultRead(get) {
28 return get(this);
29 }
30 function defaultWrite(get, set, arg) {
31 return set(this, typeof arg === 'function' ? arg(get(this)) : arg);
32 }
33
34 function _unsupportedIterableToArray(o, minLen) {
35 if (!o) return;
36 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
37 var n = Object.prototype.toString.call(o).slice(8, -1);
38 if (n === "Object" && o.constructor) n = o.constructor.name;
39 if (n === "Map" || n === "Set") return Array.from(o);
40 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
41 }
42 function _arrayLikeToArray(arr, len) {
43 if (len == null || len > arr.length) len = arr.length;
44 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
45 return arr2;
46 }
47 function _createForOfIteratorHelperLoose(o, allowArrayLike) {
48 var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
49 if (it) return (it = it.call(o)).next.bind(it);
50 if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
51 if (it) o = it;
52 var i = 0;
53 return function () {
54 if (i >= o.length) return {
55 done: true
56 };
57 return {
58 done: false,
59 value: o[i++]
60 };
61 };
62 }
63 throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
64 }
65
66 var isSelfAtom = function isSelfAtom(atom, a) {
67 return atom.unstable_is ? atom.unstable_is(a) : a === atom;
68 };
69 var hasInitialValue = function hasInitialValue(atom) {
70 return 'init' in atom;
71 };
72 var isActuallyWritableAtom = function isActuallyWritableAtom(atom) {
73 return !!atom.write;
74 };
75 var createPendingPair = function createPendingPair() {
76 return [new Set(), new Set()];
77 };
78 var addPending = function addPending(pendingPair, pending) {
79 (pendingPair[0] || pendingPair[1]).add(pending);
80 };
81 var flushPending = function flushPending(pendingPair, isAsync) {
82 var pendingSet;
83 if (isAsync) {
84 if (pendingPair[0]) {
85 return;
86 }
87 pendingSet = pendingPair[1];
88 } else {
89 if (!pendingPair[0]) {
90 throw new Error('[Bug] cannot sync flush twice');
91 }
92 pendingSet = pendingPair[0];
93 }
94 var flushed = new Set();
95 while (pendingSet.size) {
96 var copy = new Set(pendingSet);
97 pendingSet.clear();
98 copy.forEach(function (pending) {
99 if (typeof pending === 'function') {
100 pending();
101 } else {
102 var _atom = pending[0],
103 atomState = pending[1];
104 if (!flushed.has(_atom) && atomState.m) {
105 atomState.m.l.forEach(function (listener) {
106 return listener();
107 });
108 flushed.add(_atom);
109 }
110 }
111 });
112 }
113 pendingPair[0] = undefined;
114 return flushed;
115 };
116 var CONTINUE_PROMISE = Symbol('CONTINUE_PROMISE' );
117 var PENDING = 'pending';
118 var FULFILLED = 'fulfilled';
119 var REJECTED = 'rejected';
120 var isContinuablePromise = function isContinuablePromise(promise) {
121 return typeof promise === 'object' && promise !== null && CONTINUE_PROMISE in promise;
122 };
123 var continuablePromiseMap = new WeakMap();
124 var createContinuablePromise = function createContinuablePromise(promise, abort, complete) {
125 if (!continuablePromiseMap.has(promise)) {
126 var continuePromise;
127 var p = new Promise(function (resolve, reject) {
128 var curr = promise;
129 var onFullfilled = function onFullfilled(me) {
130 return function (v) {
131 if (curr === me) {
132 p.status = FULFILLED;
133 p.value = v;
134 resolve(v);
135 complete();
136 }
137 };
138 };
139 var onRejected = function onRejected(me) {
140 return function (e) {
141 if (curr === me) {
142 p.status = REJECTED;
143 p.reason = e;
144 reject(e);
145 complete();
146 }
147 };
148 };
149 promise.then(onFullfilled(promise), onRejected(promise));
150 continuePromise = function continuePromise(nextPromise, nextAbort) {
151 if (nextPromise) {
152 continuablePromiseMap.set(nextPromise, p);
153 curr = nextPromise;
154 nextPromise.then(onFullfilled(nextPromise), onRejected(nextPromise));
155 }
156 abort();
157 abort = nextAbort;
158 };
159 });
160 p.status = PENDING;
161 p[CONTINUE_PROMISE] = continuePromise;
162 continuablePromiseMap.set(promise, p);
163 }
164 return continuablePromiseMap.get(promise);
165 };
166 var isPromiseLike = function isPromiseLike(x) {
167 return typeof (x == null ? void 0 : x.then) === 'function';
168 };
169 var getPendingContinuablePromise = function getPendingContinuablePromise(atomState) {
170 var _s;
171 var value = (_s = atomState.s) == null ? void 0 : _s.v;
172 if (isContinuablePromise(value) && value.status === PENDING) {
173 return value;
174 }
175 return null;
176 };
177 var returnAtomValue = function returnAtomValue(atomState) {
178 if ('e' in atomState.s) {
179 throw atomState.s.e;
180 }
181 return atomState.s.v;
182 };
183 var setAtomStateValueOrPromise = function setAtomStateValueOrPromise(atomState, valueOrPromise, abortPromise, completePromise) {
184 if (abortPromise === void 0) {
185 abortPromise = function abortPromise() {};
186 }
187 if (completePromise === void 0) {
188 completePromise = function completePromise() {};
189 }
190 var pendingPromise = getPendingContinuablePromise(atomState);
191 if (isPromiseLike(valueOrPromise)) {
192 if (pendingPromise) {
193 if (pendingPromise !== valueOrPromise) {
194 pendingPromise[CONTINUE_PROMISE](valueOrPromise, abortPromise);
195 }
196 } else {
197 var continuablePromise = createContinuablePromise(valueOrPromise, abortPromise, completePromise);
198 atomState.s = {
199 v: continuablePromise
200 };
201 }
202 } else {
203 if (pendingPromise) {
204 pendingPromise[CONTINUE_PROMISE](Promise.resolve(valueOrPromise), abortPromise);
205 }
206 atomState.s = {
207 v: valueOrPromise
208 };
209 }
210 };
211 var createStore = function createStore() {
212 var atomStateMap = new WeakMap();
213 var getAtomState = function getAtomState(atom) {
214 var atomState = atomStateMap.get(atom);
215 if (!atomState) {
216 atomState = {
217 d: new Map(),
218 t: new Set()
219 };
220 atomStateMap.set(atom, atomState);
221 }
222 return atomState;
223 };
224 var clearDependencies = function clearDependencies(atom) {
225 var atomState = getAtomState(atom);
226 for (var _iterator = _createForOfIteratorHelperLoose(atomState.d.keys()), _step; !(_step = _iterator()).done;) {
227 var a = _step.value;
228 getAtomState(a).t.delete(atom);
229 }
230 atomState.d.clear();
231 };
232 var addDependency = function addDependency(atom, a, aState, isSync) {
233 if (a === atom) {
234 throw new Error('[Bug] atom cannot depend on itself');
235 }
236 var atomState = getAtomState(atom);
237 atomState.d.set(a, aState.s);
238 aState.t.add(atom);
239 if (!isSync && atomState.m) {
240 var pendingPair = createPendingPair();
241 mountDependencies(pendingPair, atomState);
242 flushPending(pendingPair);
243 }
244 };
245 var readAtomState = function readAtomState(atom, force) {
246 var atomState = getAtomState(atom);
247 if (!force && 's' in atomState) {
248 if (atomState.m) {
249 return atomState;
250 }
251 if (Array.from(atomState.d).every(function (_ref) {
252 var a = _ref[0],
253 s = _ref[1];
254 var aState = readAtomState(a);
255 return 'v' in s && 'v' in aState.s && Object.is(s.v, aState.s.v);
256 })) {
257 return atomState;
258 }
259 }
260 clearDependencies(atom);
261 var isSync = true;
262 var getter = function getter(a) {
263 if (isSelfAtom(atom, a)) {
264 var _aState = getAtomState(a);
265 if (!_aState.s) {
266 if (hasInitialValue(a)) {
267 setAtomStateValueOrPromise(_aState, a.init);
268 } else {
269 throw new Error('no atom init');
270 }
271 }
272 return returnAtomValue(_aState);
273 }
274 var aState = readAtomState(a);
275 addDependency(atom, a, aState, isSync);
276 return returnAtomValue(aState);
277 };
278 var controller;
279 var setSelf;
280 var options = {
281 get signal() {
282 if (!controller) {
283 controller = new AbortController();
284 }
285 return controller.signal;
286 },
287 get setSelf() {
288 if (!isActuallyWritableAtom(atom)) {
289 console.warn('setSelf function cannot be used with read-only atom');
290 }
291 if (!setSelf && isActuallyWritableAtom(atom)) {
292 setSelf = function setSelf() {
293 if (isSync) {
294 console.warn('setSelf function cannot be called in sync');
295 }
296 if (!isSync) {
297 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
298 args[_key] = arguments[_key];
299 }
300 return writeAtom.apply(void 0, [atom].concat(args));
301 }
302 };
303 }
304 return setSelf;
305 }
306 };
307 try {
308 var valueOrPromise = atom.read(getter, options);
309 setAtomStateValueOrPromise(atomState, valueOrPromise, function () {
310 var _controller;
311 return (_controller = controller) == null ? void 0 : _controller.abort();
312 }, function () {
313 if (atomState.m) {
314 var pendingPair = createPendingPair();
315 mountDependencies(pendingPair, atomState);
316 flushPending(pendingPair);
317 }
318 });
319 return atomState;
320 } catch (error) {
321 atomState.s = {
322 e: error
323 };
324 return atomState;
325 } finally {
326 isSync = false;
327 }
328 };
329 var readAtom = function readAtom(atom) {
330 return returnAtomValue(readAtomState(atom));
331 };
332 var recomputeDependents = function recomputeDependents(pendingPair, atom) {
333 var topsortedAtoms = [];
334 var markedAtoms = new Set();
335 var visit = function visit(n) {
336 if (markedAtoms.has(n)) {
337 return;
338 }
339 markedAtoms.add(n);
340 for (var _iterator2 = _createForOfIteratorHelperLoose(getAtomState(n).t), _step2; !(_step2 = _iterator2()).done;) {
341 var m = _step2.value;
342 if (n !== m) {
343 visit(m);
344 }
345 }
346 topsortedAtoms.push(n);
347 };
348 visit(atom);
349 var changedAtoms = new Set([atom]);
350 for (var i = topsortedAtoms.length - 1; i >= 0; --i) {
351 var a = topsortedAtoms[i];
352 var aState = getAtomState(a);
353 var prev = aState.s;
354 var hasChangedDeps = false;
355 for (var _iterator3 = _createForOfIteratorHelperLoose(aState.d.keys()), _step3; !(_step3 = _iterator3()).done;) {
356 var dep = _step3.value;
357 if (dep !== a && changedAtoms.has(dep)) {
358 hasChangedDeps = true;
359 break;
360 }
361 }
362 if (hasChangedDeps) {
363 if (aState.m || getPendingContinuablePromise(aState)) {
364 readAtomState(a, true);
365 mountDependencies(pendingPair, aState);
366 if (!prev || !('v' in prev) || !('v' in aState.s) || !Object.is(prev.v, aState.s.v)) {
367 addPending(pendingPair, [a, aState]);
368 changedAtoms.add(a);
369 }
370 }
371 }
372 }
373 };
374 var writeAtomState = function writeAtomState(pendingPair, atom) {
375 var getter = function getter(a) {
376 return returnAtomValue(readAtomState(a));
377 };
378 var setter = function setter(a) {
379 var r;
380 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
381 args[_key3 - 1] = arguments[_key3];
382 }
383 if (isSelfAtom(atom, a)) {
384 if (!hasInitialValue(a)) {
385 throw new Error('atom not writable');
386 }
387 var aState = getAtomState(a);
388 var prev = aState.s;
389 var v = args[0];
390 setAtomStateValueOrPromise(aState, v);
391 mountDependencies(pendingPair, aState);
392 var curr = aState.s;
393 if (!prev || !('v' in prev) || !('v' in curr) || !Object.is(prev.v, curr.v)) {
394 addPending(pendingPair, [a, aState]);
395 recomputeDependents(pendingPair, a);
396 }
397 } else {
398 r = writeAtomState.apply(void 0, [pendingPair, a].concat(args));
399 }
400 flushPending(pendingPair, true);
401 return r;
402 };
403 for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
404 args[_key2 - 2] = arguments[_key2];
405 }
406 var result = atom.write.apply(atom, [getter, setter].concat(args));
407 return result;
408 };
409 var writeAtom = function writeAtom(atom) {
410 var pendingPair = createPendingPair();
411 for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
412 args[_key4 - 1] = arguments[_key4];
413 }
414 var result = writeAtomState.apply(void 0, [pendingPair, atom].concat(args));
415 flushPending(pendingPair);
416 return result;
417 };
418 var mountDependencies = function mountDependencies(pendingPair, atomState) {
419 if (atomState.m && !getPendingContinuablePromise(atomState)) {
420 for (var _iterator4 = _createForOfIteratorHelperLoose(atomState.d.keys()), _step4; !(_step4 = _iterator4()).done;) {
421 var a = _step4.value;
422 if (!atomState.m.d.has(a)) {
423 mountAtom(pendingPair, a);
424 atomState.m.d.add(a);
425 }
426 }
427 for (var _iterator5 = _createForOfIteratorHelperLoose(atomState.m.d || []), _step5; !(_step5 = _iterator5()).done;) {
428 var _a = _step5.value;
429 if (!atomState.d.has(_a)) {
430 unmountAtom(pendingPair, _a);
431 atomState.m.d.delete(_a);
432 }
433 }
434 }
435 };
436 var mountAtom = function mountAtom(pendingPair, atom) {
437 var atomState = getAtomState(atom);
438 if (!atomState.m) {
439 readAtomState(atom);
440 for (var _iterator6 = _createForOfIteratorHelperLoose(atomState.d.keys()), _step6; !(_step6 = _iterator6()).done;) {
441 var a = _step6.value;
442 mountAtom(pendingPair, a);
443 }
444 atomState.m = {
445 l: new Set(),
446 d: new Set(atomState.d.keys())
447 };
448 if (isActuallyWritableAtom(atom) && atom.onMount) {
449 var mounted = atomState.m;
450 var onMount = atom.onMount;
451 addPending(pendingPair, function () {
452 var onUnmount = onMount(function () {
453 for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
454 args[_key5] = arguments[_key5];
455 }
456 return writeAtomState.apply(void 0, [pendingPair, atom].concat(args));
457 });
458 if (onUnmount) {
459 mounted.u = onUnmount;
460 }
461 });
462 }
463 }
464 return atomState.m;
465 };
466 var unmountAtom = function unmountAtom(pendingPair, atom) {
467 var atomState = getAtomState(atom);
468 if (atomState.m && !atomState.m.l.size && !Array.from(atomState.t).some(function (a) {
469 return getAtomState(a).m;
470 })) {
471 var onUnmount = atomState.m.u;
472 if (onUnmount) {
473 addPending(pendingPair, onUnmount);
474 }
475 delete atomState.m;
476 for (var _iterator7 = _createForOfIteratorHelperLoose(atomState.d.keys()), _step7; !(_step7 = _iterator7()).done;) {
477 var a = _step7.value;
478 unmountAtom(pendingPair, a);
479 }
480 var pendingPromise = getPendingContinuablePromise(atomState);
481 if (pendingPromise) {
482 pendingPromise[CONTINUE_PROMISE](undefined, function () {});
483 }
484 }
485 };
486 var subscribeAtom = function subscribeAtom(atom, listener) {
487 var pendingPair = createPendingPair();
488 var mounted = mountAtom(pendingPair, atom);
489 flushPending(pendingPair);
490 var listeners = mounted.l;
491 listeners.add(listener);
492 return function () {
493 listeners.delete(listener);
494 var pendingPair = createPendingPair();
495 unmountAtom(pendingPair, atom);
496 flushPending(pendingPair);
497 };
498 };
499 {
500 var store = {
501 get: readAtom,
502 set: writeAtom,
503 sub: subscribeAtom,
504 dev4_get_internal_weak_map: function dev4_get_internal_weak_map() {
505 return atomStateMap;
506 },
507 dev4_override_method: function dev4_override_method(key, fn) {
508 store[key] = fn;
509 }
510 };
511 return store;
512 }
513 };
514 var defaultStore;
515 var getDefaultStore = function getDefaultStore() {
516 if (!defaultStore) {
517 defaultStore = createStore();
518 {
519 var _ref2;
520 (_ref2 = globalThis).__JOTAI_DEFAULT_STORE__ || (_ref2.__JOTAI_DEFAULT_STORE__ = defaultStore);
521 if (globalThis.__JOTAI_DEFAULT_STORE__ !== defaultStore) {
522 console.warn('Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044');
523 }
524 }
525 }
526 return defaultStore;
527 };
528
529 exports.atom = atom;
530 exports.createStore = createStore;
531 exports.getDefaultStore = getDefaultStore;
532
533}));