UNPKG

jotai

Version:

👻 Next gen state management that will spook you

521 lines (516 loc) • 16.5 kB
'use strict'; var keyCount = 0; function atom(read, write) { var key = "atom" + ++keyCount; var config = { toString: function toString() { return key; } }; if (typeof read === 'function') { config.read = read; } else { config.init = read; config.read = function (get) { return get(config); }; config.write = function (get, set, arg) { return set(config, typeof arg === 'function' ? arg(get(config)) : arg); }; } if (write) { config.write = write; } return config; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var hasInitialValue = function hasInitialValue(atom) { return 'init' in atom; }; var isActuallyWritableAtom = function isActuallyWritableAtom(atom) { return !!atom.write; }; var cancelPromiseMap = new WeakMap(); var registerCancelPromise = function registerCancelPromise(promise, cancel) { cancelPromiseMap.set(promise, cancel); promise.catch(function () {}).finally(function () { return cancelPromiseMap.delete(promise); }); }; var cancelPromise = function cancelPromise(promise, next) { var cancel = cancelPromiseMap.get(promise); if (cancel) { cancelPromiseMap.delete(promise); cancel(next); } }; var isEqualAtomValue = function isEqualAtomValue(a, b) { return 'v' in a && 'v' in b && Object.is(a.v, b.v); }; var isEqualAtomError = function isEqualAtomError(a, b) { return 'e' in a && 'e' in b && Object.is(a.e, b.e); }; var hasPromiseAtomValue = function hasPromiseAtomValue(a) { return 'v' in a && a.v instanceof Promise; }; var returnAtomValue = function returnAtomValue(atomState) { if ('e' in atomState) { throw atomState.e; } return atomState.v; }; var createStore = function createStore() { var atomStateMap = new WeakMap(); var mountedMap = new WeakMap(); var pendingMap = new Map(); var stateListeners; var mountedAtoms; if (process.env.NODE_ENV !== "production") { stateListeners = new Set(); mountedAtoms = new Set(); } var getAtomState = function getAtomState(atom) { return atomStateMap.get(atom); }; var setAtomState = function setAtomState(atom, atomState) { if (process.env.NODE_ENV !== "production") { Object.freeze(atomState); } var prevAtomState = atomStateMap.get(atom); atomStateMap.set(atom, atomState); if (!pendingMap.has(atom)) { pendingMap.set(atom, prevAtomState); } if (prevAtomState && hasPromiseAtomValue(prevAtomState)) { var _next = 'v' in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e); cancelPromise(prevAtomState.v, _next); } }; var updateDependencies = function updateDependencies(atom, nextAtomState, depSet) { var dependencies = new Map(); var changed = false; depSet.forEach(function (a) { var aState = a === atom ? nextAtomState : getAtomState(a); if (aState) { dependencies.set(a, aState); if (nextAtomState.d.get(a) !== aState) { changed = true; } } else if (process.env.NODE_ENV !== "production") { console.warn('[Bug] atom state not found'); } }); if (changed || nextAtomState.d.size !== dependencies.size) { nextAtomState.d = dependencies; } }; var setAtomValue = function setAtomValue(atom, value, depSet) { var prevAtomState = getAtomState(atom); var nextAtomState = { d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(), v: value }; if (depSet) { updateDependencies(atom, nextAtomState, depSet); } if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { return prevAtomState; } setAtomState(atom, nextAtomState); return nextAtomState; }; var setAtomError = function setAtomError(atom, error, depSet) { var prevAtomState = getAtomState(atom); var nextAtomState = { d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(), e: error }; if (depSet) { updateDependencies(atom, nextAtomState, depSet); } if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { return prevAtomState; } setAtomState(atom, nextAtomState); return nextAtomState; }; var readAtomState = function readAtomState(atom, force) { if (!force) { var atomState = getAtomState(atom); if (atomState) { atomState.d.forEach(function (_, a) { if (a !== atom && !mountedMap.has(a)) { readAtomState(a); } }); if (Array.from(atomState.d).every(function (_ref) { var a = _ref[0], s = _ref[1]; return a === atom || getAtomState(a) === s; })) { return atomState; } } } var depSet = new Set(); var isSync = true; var getter = function getter(a) { depSet.add(a); if (a === atom) { var _aState = getAtomState(a); if (_aState) { return returnAtomValue(_aState); } if (hasInitialValue(a)) { return a.init; } throw new Error('no atom init'); } var aState = readAtomState(a); return returnAtomValue(aState); }; var controller; var setSelf; var options = { get signal() { if (!controller) { controller = new AbortController(); } return controller.signal; }, get setSelf() { if (process.env.NODE_ENV !== "production" && !isActuallyWritableAtom(atom)) { console.warn('setSelf function cannot be used with read-only atom'); } if (!setSelf && isActuallyWritableAtom(atom)) { setSelf = function setSelf() { if (process.env.NODE_ENV !== "production" && isSync) { console.warn('setSelf function cannot be called in sync'); } if (!isSync) { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return writeAtom.apply(void 0, [atom].concat(args)); } }; } return setSelf; } }; try { var value = atom.read(getter, options); if (value instanceof Promise) { var continuePromise; var promise = new Promise(function (resolve, reject) { value.then(function (v) { promise.status = 'fulfilled'; promise.value = v; resolve(v); }, function (e) { promise.status = 'rejected'; promise.reason = e; reject(e); }).finally(function () { setAtomValue(atom, promise, depSet); }); continuePromise = function continuePromise(next) { return resolve(next); }; }); promise.status = 'pending'; registerCancelPromise(promise, function (next) { var _controller; if (next) { continuePromise(next); } (_controller = controller) == null ? void 0 : _controller.abort(); }); return setAtomValue(atom, promise, depSet); } return setAtomValue(atom, value, depSet); } catch (error) { return setAtomError(atom, error, depSet); } finally { isSync = false; } }; var readAtom = function readAtom(atom) { return returnAtomValue(readAtomState(atom)); }; var addAtom = function addAtom(atom) { var mounted = mountedMap.get(atom); if (!mounted) { mounted = mountAtom(atom); } return mounted; }; var canUnmountAtom = function canUnmountAtom(atom, mounted) { return !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom)); }; var delAtom = function delAtom(atom) { var mounted = mountedMap.get(atom); if (mounted && canUnmountAtom(atom, mounted)) { unmountAtom(atom); } }; var recomputeDependents = function recomputeDependents(atom) { var mounted = mountedMap.get(atom); mounted == null ? void 0 : mounted.t.forEach(function (dependent) { if (dependent !== atom) { var prevAtomState = getAtomState(dependent); var nextAtomState = readAtomState(dependent); if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) { recomputeDependents(dependent); } } }); }; var writeAtomState = function writeAtomState(atom) { var isSync = true; var getter = function getter(a) { return returnAtomValue(readAtomState(a)); }; var setter = function setter(a) { var r; for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } if (a === atom) { if (!hasInitialValue(a)) { throw new Error('atom not writable'); } var prevAtomState = getAtomState(a); var nextAtomState = setAtomValue(a, args[0]); if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) { recomputeDependents(a); } } else { r = writeAtomState.apply(void 0, [a].concat(args)); } if (!isSync) { flushPending(); } return r; }; for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } var result = atom.write.apply(atom, [getter, setter].concat(args)); isSync = false; return result; }; var writeAtom = function writeAtom(atom) { for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { args[_key4 - 1] = arguments[_key4]; } var result = writeAtomState.apply(void 0, [atom].concat(args)); flushPending(); return result; }; var mountAtom = function mountAtom(atom, initialDependent) { var mounted = { t: new Set(initialDependent && [initialDependent]), l: new Set() }; mountedMap.set(atom, mounted); if (process.env.NODE_ENV !== "production") { mountedAtoms.add(atom); } readAtomState(atom).d.forEach(function (_, a) { var aMounted = mountedMap.get(a); if (aMounted) { aMounted.t.add(atom); } else { if (a !== atom) { mountAtom(a, atom); } } }); readAtomState(atom); if (isActuallyWritableAtom(atom) && atom.onMount) { var onUnmount = atom.onMount(function () { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } return writeAtom.apply(void 0, [atom].concat(args)); }); if (onUnmount) { mounted.u = onUnmount; } } return mounted; }; var unmountAtom = function unmountAtom(atom) { var _mountedMap$get; var onUnmount = (_mountedMap$get = mountedMap.get(atom)) == null ? void 0 : _mountedMap$get.u; if (onUnmount) { onUnmount(); } mountedMap.delete(atom); if (process.env.NODE_ENV !== "production") { mountedAtoms.delete(atom); } var atomState = getAtomState(atom); if (atomState) { if (hasPromiseAtomValue(atomState)) { cancelPromise(atomState.v); } atomState.d.forEach(function (_, a) { if (a !== atom) { var mounted = mountedMap.get(a); if (mounted) { mounted.t.delete(atom); if (canUnmountAtom(a, mounted)) { unmountAtom(a); } } } }); } else if (process.env.NODE_ENV !== "production") { console.warn('[Bug] could not find atom state to unmount', atom); } }; var mountDependencies = function mountDependencies(atom, atomState, prevDependencies) { var depSet = new Set(atomState.d.keys()); prevDependencies == null ? void 0 : prevDependencies.forEach(function (_, a) { if (depSet.has(a)) { depSet.delete(a); return; } var mounted = mountedMap.get(a); if (mounted) { mounted.t.delete(atom); if (canUnmountAtom(a, mounted)) { unmountAtom(a); } } }); depSet.forEach(function (a) { var mounted = mountedMap.get(a); if (mounted) { mounted.t.add(atom); } else if (mountedMap.has(atom)) { mountAtom(a, atom); } }); }; var flushPending = function flushPending() { while (pendingMap.size) { var pending = Array.from(pendingMap); pendingMap.clear(); pending.forEach(function (_ref2) { var atom = _ref2[0], prevAtomState = _ref2[1]; var atomState = getAtomState(atom); if (atomState) { if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) { mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d); } var mounted = mountedMap.get(atom); mounted == null ? void 0 : mounted.l.forEach(function (listener) { return listener(); }); } else if (process.env.NODE_ENV !== "production") { console.warn('[Bug] no atom state to flush'); } }); } if (process.env.NODE_ENV !== "production") { stateListeners.forEach(function (l) { return l(); }); } }; var subscribeAtom = function subscribeAtom(atom, listener) { var mounted = addAtom(atom); var listeners = mounted.l; listeners.add(listener); flushPending(); return function () { listeners.delete(listener); delAtom(atom); }; }; var restoreAtoms = function restoreAtoms(values) { for (var _iterator = _createForOfIteratorHelperLoose(values), _step; !(_step = _iterator()).done;) { var _step$value = _step.value, atom = _step$value[0], value = _step$value[1]; if (hasInitialValue(atom)) { setAtomValue(atom, value); recomputeDependents(atom); } } flushPending(); }; if (process.env.NODE_ENV !== "production") { return { get: readAtom, set: writeAtom, sub: subscribeAtom, res: restoreAtoms, dev_subscribe_state: function dev_subscribe_state(l) { stateListeners.add(l); return function () { stateListeners.delete(l); }; }, dev_get_mounted_atoms: function dev_get_mounted_atoms() { return mountedAtoms.values(); }, dev_get_atom_state: function dev_get_atom_state(a) { return atomStateMap.get(a); }, dev_get_mounted: function dev_get_mounted(a) { return mountedMap.get(a); } }; } return { get: readAtom, set: writeAtom, sub: subscribeAtom, res: restoreAtoms }; }; var defaultStore; var getDefaultStore = function getDefaultStore() { if (!defaultStore) { defaultStore = createStore(); } return defaultStore; }; exports.atom = atom; exports.createStore = createStore; exports.getDefaultStore = getDefaultStore;