UNPKG

17.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 isEqualAtomValue = function isEqualAtomValue(a, b) {
85 return 'v' in a && 'v' in b && Object.is(a.v, b.v);
86 };
87 var isEqualAtomError = function isEqualAtomError(a, b) {
88 return 'e' in a && 'e' in b && Object.is(a.e, b.e);
89 };
90 var hasPromiseAtomValue = function hasPromiseAtomValue(a) {
91 return 'v' in a && a.v instanceof Promise;
92 };
93 var returnAtomValue = function returnAtomValue(atomState) {
94 if ('e' in atomState) {
95 throw atomState.e;
96 }
97 return atomState.v;
98 };
99 var createStore = function createStore() {
100 var atomStateMap = new WeakMap();
101 var mountedMap = new WeakMap();
102 var pendingMap = new Map();
103 var stateListeners;
104 var mountedAtoms;
105 {
106 stateListeners = new Set();
107 mountedAtoms = new Set();
108 }
109 var getAtomState = function getAtomState(atom) {
110 return atomStateMap.get(atom);
111 };
112 var setAtomState = function setAtomState(atom, atomState) {
113 {
114 Object.freeze(atomState);
115 }
116 var prevAtomState = atomStateMap.get(atom);
117 atomStateMap.set(atom, atomState);
118 if (!pendingMap.has(atom)) {
119 pendingMap.set(atom, prevAtomState);
120 }
121 if (prevAtomState && hasPromiseAtomValue(prevAtomState)) {
122 var _next = 'v' in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
123 cancelPromise(prevAtomState.v, _next);
124 }
125 };
126 var updateDependencies = function updateDependencies(atom, nextAtomState, depSet) {
127 var dependencies = new Map();
128 var changed = false;
129 depSet.forEach(function (a) {
130 var aState = a === atom ? nextAtomState : getAtomState(a);
131 if (aState) {
132 dependencies.set(a, aState);
133 if (nextAtomState.d.get(a) !== aState) {
134 changed = true;
135 }
136 } else {
137 console.warn('[Bug] atom state not found');
138 }
139 });
140 if (changed || nextAtomState.d.size !== dependencies.size) {
141 nextAtomState.d = dependencies;
142 }
143 };
144 var setAtomValue = function setAtomValue(atom, value, depSet) {
145 var prevAtomState = getAtomState(atom);
146 var nextAtomState = {
147 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
148 v: value
149 };
150 if (depSet) {
151 updateDependencies(atom, nextAtomState, depSet);
152 }
153 if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
154 return prevAtomState;
155 }
156 setAtomState(atom, nextAtomState);
157 return nextAtomState;
158 };
159 var setAtomError = function setAtomError(atom, error, depSet) {
160 var prevAtomState = getAtomState(atom);
161 var nextAtomState = {
162 d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
163 e: error
164 };
165 if (depSet) {
166 updateDependencies(atom, nextAtomState, depSet);
167 }
168 if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
169 return prevAtomState;
170 }
171 setAtomState(atom, nextAtomState);
172 return nextAtomState;
173 };
174 var readAtomState = function readAtomState(atom) {
175 var atomState = getAtomState(atom);
176 if (atomState) {
177 atomState.d.forEach(function (_, a) {
178 if (a !== atom && !mountedMap.has(a)) {
179 readAtomState(a);
180 }
181 });
182 if (Array.from(atomState.d).every(function (_ref) {
183 var a = _ref[0],
184 s = _ref[1];
185 return a === atom || getAtomState(a) === s;
186 })) {
187 return atomState;
188 }
189 }
190 var depSet = new Set();
191 var isSync = true;
192 var getter = function getter(a) {
193 depSet.add(a);
194 if (a === atom) {
195 var _aState = getAtomState(a);
196 if (_aState) {
197 return returnAtomValue(_aState);
198 }
199 if (hasInitialValue(a)) {
200 return a.init;
201 }
202 throw new Error('no atom init');
203 }
204 var aState = readAtomState(a);
205 return returnAtomValue(aState);
206 };
207 var controller;
208 var setSelf;
209 var options = {
210 get signal() {
211 if (!controller) {
212 controller = new AbortController();
213 }
214 return controller.signal;
215 },
216 get setSelf() {
217 if (!isActuallyWritableAtom(atom)) {
218 console.warn('setSelf function cannot be used with read-only atom');
219 }
220 if (!setSelf && isActuallyWritableAtom(atom)) {
221 setSelf = function setSelf() {
222 if (isSync) {
223 console.warn('setSelf function cannot be called in sync');
224 }
225 if (!isSync) {
226 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
227 args[_key] = arguments[_key];
228 }
229 return writeAtom.apply(void 0, [atom].concat(args));
230 }
231 };
232 }
233 return setSelf;
234 }
235 };
236 try {
237 var value = atom.read(getter, options);
238 if (value instanceof Promise) {
239 var continuePromise;
240 var promise = new Promise(function (resolve, reject) {
241 value.then(function (v) {
242 promise.status = 'fulfilled';
243 promise.value = v;
244 resolve(v);
245 }, function (e) {
246 promise.status = 'rejected';
247 promise.reason = e;
248 reject(e);
249 }).finally(function () {
250 setAtomValue(atom, promise, depSet);
251 });
252 continuePromise = function continuePromise(next) {
253 return resolve(next);
254 };
255 });
256 promise.status = 'pending';
257 registerCancelPromise(promise, function (next) {
258 var _controller;
259 if (next) {
260 continuePromise(next);
261 }
262 (_controller = controller) == null ? void 0 : _controller.abort();
263 });
264 return setAtomValue(atom, promise, depSet);
265 }
266 return setAtomValue(atom, value, depSet);
267 } catch (error) {
268 return setAtomError(atom, error, depSet);
269 } finally {
270 isSync = false;
271 }
272 };
273 var readAtom = function readAtom(atom) {
274 return returnAtomValue(readAtomState(atom));
275 };
276 var addAtom = function addAtom(atom) {
277 var mounted = mountedMap.get(atom);
278 if (!mounted) {
279 mounted = mountAtom(atom);
280 }
281 return mounted;
282 };
283 var canUnmountAtom = function canUnmountAtom(atom, mounted) {
284 return !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
285 };
286 var delAtom = function delAtom(atom) {
287 var mounted = mountedMap.get(atom);
288 if (mounted && canUnmountAtom(atom, mounted)) {
289 unmountAtom(atom);
290 }
291 };
292 var recomputeDependents = function recomputeDependents(atom) {
293 var mounted = mountedMap.get(atom);
294 mounted == null ? void 0 : mounted.t.forEach(function (dependent) {
295 if (dependent !== atom) {
296 var prevAtomState = getAtomState(dependent);
297 var nextAtomState = readAtomState(dependent);
298 if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
299 recomputeDependents(dependent);
300 }
301 }
302 });
303 };
304 var writeAtomState = function writeAtomState(atom) {
305 var isSync = true;
306 var getter = function getter(a) {
307 return returnAtomValue(readAtomState(a));
308 };
309 var setter = function setter(a) {
310 var r;
311 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
312 args[_key3 - 1] = arguments[_key3];
313 }
314 if (a === atom) {
315 if (!hasInitialValue(a)) {
316 throw new Error('atom not writable');
317 }
318 var prevAtomState = getAtomState(a);
319 var nextAtomState = setAtomValue(a, args[0]);
320 if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
321 recomputeDependents(a);
322 }
323 } else {
324 r = writeAtomState.apply(void 0, [a].concat(args));
325 }
326 if (!isSync) {
327 flushPending();
328 }
329 return r;
330 };
331 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
332 args[_key2 - 1] = arguments[_key2];
333 }
334 var result = atom.write.apply(atom, [getter, setter].concat(args));
335 isSync = false;
336 return result;
337 };
338 var writeAtom = function writeAtom(atom) {
339 for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
340 args[_key4 - 1] = arguments[_key4];
341 }
342 var result = writeAtomState.apply(void 0, [atom].concat(args));
343 flushPending();
344 return result;
345 };
346 var mountAtom = function mountAtom(atom, initialDependent) {
347 var mounted = {
348 t: new Set(initialDependent && [initialDependent]),
349 l: new Set()
350 };
351 mountedMap.set(atom, mounted);
352 {
353 mountedAtoms.add(atom);
354 }
355 readAtomState(atom).d.forEach(function (_, a) {
356 var aMounted = mountedMap.get(a);
357 if (aMounted) {
358 aMounted.t.add(atom);
359 } else {
360 if (a !== atom) {
361 mountAtom(a, atom);
362 }
363 }
364 });
365 readAtomState(atom);
366 if (isActuallyWritableAtom(atom) && atom.onMount) {
367 var onUnmount = atom.onMount(function () {
368 for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
369 args[_key5] = arguments[_key5];
370 }
371 return writeAtom.apply(void 0, [atom].concat(args));
372 });
373 if (onUnmount) {
374 mounted.u = onUnmount;
375 }
376 }
377 return mounted;
378 };
379 var unmountAtom = function unmountAtom(atom) {
380 var _mountedMap$get;
381 var onUnmount = (_mountedMap$get = mountedMap.get(atom)) == null ? void 0 : _mountedMap$get.u;
382 if (onUnmount) {
383 onUnmount();
384 }
385 mountedMap.delete(atom);
386 {
387 mountedAtoms.delete(atom);
388 }
389 var atomState = getAtomState(atom);
390 if (atomState) {
391 if (hasPromiseAtomValue(atomState)) {
392 cancelPromise(atomState.v);
393 }
394 atomState.d.forEach(function (_, a) {
395 if (a !== atom) {
396 var mounted = mountedMap.get(a);
397 if (mounted) {
398 mounted.t.delete(atom);
399 if (canUnmountAtom(a, mounted)) {
400 unmountAtom(a);
401 }
402 }
403 }
404 });
405 } else {
406 console.warn('[Bug] could not find atom state to unmount', atom);
407 }
408 };
409 var mountDependencies = function mountDependencies(atom, atomState, prevDependencies) {
410 var depSet = new Set(atomState.d.keys());
411 prevDependencies == null ? void 0 : prevDependencies.forEach(function (_, a) {
412 if (depSet.has(a)) {
413 depSet.delete(a);
414 return;
415 }
416 var mounted = mountedMap.get(a);
417 if (mounted) {
418 mounted.t.delete(atom);
419 if (canUnmountAtom(a, mounted)) {
420 unmountAtom(a);
421 }
422 }
423 });
424 depSet.forEach(function (a) {
425 var mounted = mountedMap.get(a);
426 if (mounted) {
427 mounted.t.add(atom);
428 } else if (mountedMap.has(atom)) {
429 mountAtom(a, atom);
430 }
431 });
432 };
433 var flushPending = function flushPending() {
434 while (pendingMap.size) {
435 var pending = Array.from(pendingMap);
436 pendingMap.clear();
437 pending.forEach(function (_ref2) {
438 var atom = _ref2[0],
439 prevAtomState = _ref2[1];
440 var atomState = getAtomState(atom);
441 if (atomState) {
442 if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
443 mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
444 }
445 var mounted = mountedMap.get(atom);
446 mounted == null ? void 0 : mounted.l.forEach(function (listener) {
447 return listener();
448 });
449 } else {
450 console.warn('[Bug] no atom state to flush');
451 }
452 });
453 }
454 {
455 stateListeners.forEach(function (l) {
456 return l();
457 });
458 }
459 };
460 var subscribeAtom = function subscribeAtom(atom, listener) {
461 var mounted = addAtom(atom);
462 var listeners = mounted.l;
463 listeners.add(listener);
464 flushPending();
465 return function () {
466 listeners.delete(listener);
467 delAtom(atom);
468 };
469 };
470 var restoreAtoms = function restoreAtoms(values) {
471 for (var _iterator = _createForOfIteratorHelperLoose(values), _step; !(_step = _iterator()).done;) {
472 var _step$value = _step.value,
473 atom = _step$value[0],
474 value = _step$value[1];
475 if (hasInitialValue(atom)) {
476 setAtomValue(atom, value);
477 recomputeDependents(atom);
478 }
479 }
480 flushPending();
481 };
482 {
483 return {
484 get: readAtom,
485 set: writeAtom,
486 sub: subscribeAtom,
487 res: restoreAtoms,
488 dev_subscribe_state: function dev_subscribe_state(l) {
489 stateListeners.add(l);
490 return function () {
491 stateListeners.delete(l);
492 };
493 },
494 dev_get_mounted_atoms: function dev_get_mounted_atoms() {
495 return mountedAtoms.values();
496 },
497 dev_get_atom_state: function dev_get_atom_state(a) {
498 return atomStateMap.get(a);
499 },
500 dev_get_mounted: function dev_get_mounted(a) {
501 return mountedMap.get(a);
502 }
503 };
504 }
505 };
506 var defaultStore;
507 var getDefaultStore = function getDefaultStore() {
508 if (!defaultStore) {
509 defaultStore = createStore();
510 }
511 return defaultStore;
512 };
513
514 exports.atom = atom;
515 exports.createStore = createStore;
516 exports.getDefaultStore = getDefaultStore;
517
518}));