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