jotai
Version:
👻 Primitive and flexible state management for React
725 lines (720 loc) • 24 kB
JavaScript
;
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 = defaultRead;
config.write = defaultWrite;
}
if (write) {
config.write = write;
}
return config;
}
function defaultRead(get) {
return get(this);
}
function defaultWrite(get, set, arg) {
return set(this, typeof arg === 'function' ? arg(get(this)) : arg);
}
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 isSelfAtom = function isSelfAtom(atom, a) {
return atom.unstable_is ? atom.unstable_is(a) : a === atom;
};
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 resolvePromise = function resolvePromise(promise, value) {
promise.status = 'fulfilled';
promise.value = value;
};
var rejectPromise = function rejectPromise(promise, e) {
promise.status = 'rejected';
promise.reason = e;
};
var isPromiseLike = function isPromiseLike(x) {
return typeof (x == null ? void 0 : x.then) === 'function';
};
var isEqualAtomValue = function isEqualAtomValue(a, b) {
return !!a && 'v' in a && 'v' in b && Object.is(a.v, b.v);
};
var isEqualAtomError = function isEqualAtomError(a, b) {
return !!a && 'e' in a && 'e' in b && Object.is(a.e, b.e);
};
var hasPromiseAtomValue = function hasPromiseAtomValue(a) {
return !!a && 'v' in a && a.v instanceof Promise;
};
var isEqualPromiseAtomValue = function isEqualPromiseAtomValue(a, b) {
return 'v' in a && 'v' in b && a.v.orig && a.v.orig === b.v.orig;
};
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 pendingStack = [];
var pendingMap = new WeakMap();
var storeListenersRev2;
var mountedAtoms;
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2 = new Set();
mountedAtoms = new Set();
}
var getAtomState = function getAtomState(atom) {
return atomStateMap.get(atom);
};
var addPendingDependent = function addPendingDependent(atom, atomState) {
atomState.d.forEach(function (_, a) {
if (!pendingMap.has(a)) {
var _pendingStack;
var aState = getAtomState(a);
(_pendingStack = pendingStack[pendingStack.length - 1]) == null || _pendingStack.add(a);
pendingMap.set(a, [aState, new Set()]);
if (aState) {
addPendingDependent(a, aState);
}
}
pendingMap.get(a)[1].add(atom);
});
};
var setAtomState = function setAtomState(atom, atomState) {
if (process.env.NODE_ENV !== 'production') {
Object.freeze(atomState);
}
var prevAtomState = getAtomState(atom);
atomStateMap.set(atom, atomState);
if (!pendingMap.has(atom)) {
var _pendingStack2;
(_pendingStack2 = pendingStack[pendingStack.length - 1]) == null || _pendingStack2.add(atom);
pendingMap.set(atom, [prevAtomState, new Set()]);
addPendingDependent(atom, atomState);
}
if (hasPromiseAtomValue(prevAtomState)) {
var _next = 'v' in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
if (prevAtomState.v !== _next) {
cancelPromise(prevAtomState.v, _next);
}
}
};
var updateDependencies = function updateDependencies(atom, nextAtomState, nextDependencies, keepPreviousDependencies) {
var dependencies = new Map(keepPreviousDependencies ? nextAtomState.d : null);
var changed = false;
nextDependencies.forEach(function (aState, a) {
if (!aState && isSelfAtom(atom, a)) {
aState = nextAtomState;
}
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, nextDependencies, keepPreviousDependencies) {
var prevAtomState = getAtomState(atom);
var nextAtomState = {
d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
v: value
};
if (nextDependencies) {
updateDependencies(atom, nextAtomState, nextDependencies, keepPreviousDependencies);
}
if (isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
if (hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) {
if (prevAtomState.d === nextAtomState.d) {
return prevAtomState;
} else {
nextAtomState.v = prevAtomState.v;
}
}
setAtomState(atom, nextAtomState);
return nextAtomState;
};
var setAtomValueOrPromise = function setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, abortPromise) {
if (isPromiseLike(valueOrPromise)) {
var continuePromise;
var updatePromiseDependencies = function updatePromiseDependencies() {
var prevAtomState = getAtomState(atom);
if (!hasPromiseAtomValue(prevAtomState) || prevAtomState.v !== promise) {
return;
}
var nextAtomState = setAtomValue(atom, promise, nextDependencies);
if (mountedMap.has(atom) && prevAtomState.d !== nextAtomState.d) {
mountDependencies(atom, nextAtomState, prevAtomState.d);
}
};
var promise = new Promise(function (resolve, reject) {
var settled = false;
valueOrPromise.then(function (v) {
if (!settled) {
settled = true;
resolvePromise(promise, v);
resolve(v);
updatePromiseDependencies();
}
}, function (e) {
if (!settled) {
settled = true;
rejectPromise(promise, e);
reject(e);
updatePromiseDependencies();
}
});
continuePromise = function continuePromise(next) {
if (!settled) {
settled = true;
next.then(function (v) {
return resolvePromise(promise, v);
}, function (e) {
return rejectPromise(promise, e);
});
resolve(next);
}
};
});
promise.orig = valueOrPromise;
promise.status = 'pending';
registerCancelPromise(promise, function (next) {
if (next) {
continuePromise(next);
}
abortPromise == null || abortPromise();
});
return setAtomValue(atom, promise, nextDependencies, true);
}
return setAtomValue(atom, valueOrPromise, nextDependencies);
};
var setAtomError = function setAtomError(atom, error, nextDependencies) {
var prevAtomState = getAtomState(atom);
var nextAtomState = {
d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
e: error
};
if (nextDependencies) {
updateDependencies(atom, nextAtomState, nextDependencies);
}
if (isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
setAtomState(atom, nextAtomState);
return nextAtomState;
};
var readAtomState = function readAtomState(atom, force) {
var atomState = getAtomState(atom);
if (!force && atomState) {
if (mountedMap.has(atom)) {
return atomState;
}
if (Array.from(atomState.d).every(function (_ref) {
var a = _ref[0],
s = _ref[1];
if (a === atom) {
return true;
}
var aState = readAtomState(a);
return aState === s || isEqualAtomValue(aState, s);
})) {
return atomState;
}
}
var nextDependencies = new Map();
var isSync = true;
var getter = function getter(a) {
if (isSelfAtom(atom, a)) {
var _aState = getAtomState(a);
if (_aState) {
nextDependencies.set(a, _aState);
return returnAtomValue(_aState);
}
if (hasInitialValue(a)) {
nextDependencies.set(a, undefined);
return a.init;
}
throw new Error('no atom init');
}
var aState = readAtomState(a);
nextDependencies.set(a, aState);
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 valueOrPromise = atom.read(getter, options);
return setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, function () {
var _controller;
return (_controller = controller) == null ? void 0 : _controller.abort();
});
} catch (error) {
return setAtomError(atom, error, nextDependencies);
} 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 getDependents = function getDependents(a) {
var _mountedMap$get, _pendingMap$get;
var dependents = new Set((_mountedMap$get = mountedMap.get(a)) == null ? void 0 : _mountedMap$get.t);
(_pendingMap$get = pendingMap.get(a)) == null || _pendingMap$get[1].forEach(function (dependent) {
dependents.add(dependent);
});
return dependents;
};
var topsortedAtoms = new Array();
var markedAtoms = new Set();
var visit = function visit(n) {
if (markedAtoms.has(n)) {
return;
}
markedAtoms.add(n);
for (var _iterator = _createForOfIteratorHelperLoose(getDependents(n)), _step; !(_step = _iterator()).done;) {
var m = _step.value;
if (n !== m) {
visit(m);
}
}
topsortedAtoms.push(n);
};
visit(atom);
var changedAtoms = new Set([atom]);
for (var i = topsortedAtoms.length - 1; i >= 0; --i) {
var a = topsortedAtoms[i];
var _prevAtomState = getAtomState(a);
if (!_prevAtomState) {
continue;
}
var hasChangedDeps = false;
for (var _iterator2 = _createForOfIteratorHelperLoose(_prevAtomState.d.keys()), _step2; !(_step2 = _iterator2()).done;) {
var dep = _step2.value;
if (dep !== a && changedAtoms.has(dep)) {
hasChangedDeps = true;
break;
}
}
if (hasChangedDeps) {
var nextAtomState = readAtomState(a, true);
if (!isEqualAtomValue(_prevAtomState, nextAtomState)) {
changedAtoms.add(a);
}
}
}
};
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 (isSelfAtom(atom, a)) {
if (!hasInitialValue(a)) {
throw new Error('atom not writable');
}
var _prevAtomState2 = getAtomState(a);
var nextAtomState = setAtomValueOrPromise(a, args[0]);
if (!isEqualAtomValue(_prevAtomState2, nextAtomState)) {
recomputeDependents(a);
}
} else {
r = writeAtomState.apply(void 0, [a].concat(args));
}
if (!isSync) {
var flushed = flushPending([a]);
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2.forEach(function (l) {
return l({
type: 'async-write',
flushed: flushed
});
});
}
}
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) {
pendingStack.push(new Set([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));
var flushed = flushPending(pendingStack.pop());
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2.forEach(function (l) {
return l({
type: 'write',
flushed: flushed
});
});
}
return result;
};
var mountAtom = function mountAtom(atom, initialDependent, onMountQueue) {
var _getAtomState;
var queue = onMountQueue || [];
(_getAtomState = getAtomState(atom)) == null || _getAtomState.d.forEach(function (_, a) {
var aMounted = mountedMap.get(a);
if (aMounted) {
aMounted.t.add(atom);
} else {
if (a !== atom) {
mountAtom(a, atom, queue);
}
}
});
readAtomState(atom);
var mounted = {
t: new Set(initialDependent && [initialDependent]),
l: new Set()
};
mountedMap.set(atom, mounted);
if (process.env.NODE_ENV !== 'production') {
mountedAtoms.add(atom);
}
if (isActuallyWritableAtom(atom) && atom.onMount) {
var onMount = atom.onMount;
queue.push(function () {
var onUnmount = 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;
}
});
}
if (!onMountQueue) {
queue.forEach(function (f) {
return f();
});
}
return mounted;
};
var unmountAtom = function unmountAtom(atom) {
var _mountedMap$get2;
var onUnmount = (_mountedMap$get2 = mountedMap.get(atom)) == null ? void 0 : _mountedMap$get2.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());
var maybeUnmountAtomSet = new Set();
prevDependencies == null || prevDependencies.forEach(function (_, a) {
if (depSet.has(a)) {
depSet.delete(a);
return;
}
maybeUnmountAtomSet.add(a);
var mounted = mountedMap.get(a);
if (mounted) {
mounted.t.delete(atom);
}
});
depSet.forEach(function (a) {
var mounted = mountedMap.get(a);
if (mounted) {
mounted.t.add(atom);
} else if (mountedMap.has(atom)) {
mountAtom(a, atom);
}
});
maybeUnmountAtomSet.forEach(function (a) {
var mounted = mountedMap.get(a);
if (mounted && canUnmountAtom(a, mounted)) {
unmountAtom(a);
}
});
};
var flushPending = function flushPending(pendingAtoms) {
var flushed;
if (process.env.NODE_ENV !== 'production') {
flushed = new Set();
}
var pending = [];
var collectPending = function collectPending(pendingAtom) {
var _getAtomState2;
if (!pendingMap.has(pendingAtom)) {
return;
}
var _ref2 = pendingMap.get(pendingAtom),
prevAtomState = _ref2[0],
dependents = _ref2[1];
pendingMap.delete(pendingAtom);
pending.push([pendingAtom, prevAtomState]);
dependents.forEach(collectPending);
(_getAtomState2 = getAtomState(pendingAtom)) == null || _getAtomState2.d.forEach(function (_, a) {
return collectPending(a);
});
};
pendingAtoms.forEach(collectPending);
pending.forEach(function (_ref3) {
var atom = _ref3[0],
prevAtomState = _ref3[1];
var atomState = getAtomState(atom);
if (!atomState) {
if (process.env.NODE_ENV !== 'production') {
console.warn('[Bug] no atom state to flush');
}
return;
}
if (atomState !== prevAtomState) {
var mounted = mountedMap.get(atom);
if (mounted && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
if (mounted && !(!hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
mounted.l.forEach(function (listener) {
return listener();
});
if (process.env.NODE_ENV !== 'production') {
flushed.add(atom);
}
}
}
});
if (process.env.NODE_ENV !== 'production') {
return flushed;
}
};
var subscribeAtom = function subscribeAtom(atom, listener) {
var mounted = addAtom(atom);
var flushed = flushPending([atom]);
var listeners = mounted.l;
listeners.add(listener);
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2.forEach(function (l) {
return l({
type: 'sub',
flushed: flushed
});
});
}
return function () {
listeners.delete(listener);
delAtom(atom);
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2.forEach(function (l) {
return l({
type: 'unsub'
});
});
}
};
};
if (process.env.NODE_ENV !== 'production') {
return {
get: readAtom,
set: writeAtom,
sub: subscribeAtom,
dev_subscribe_store: function dev_subscribe_store(l, rev) {
if (rev !== 2) {
throw new Error('The current StoreListener revision is 2.');
}
storeListenersRev2.add(l);
return function () {
storeListenersRev2.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);
},
dev_restore_atoms: function dev_restore_atoms(values) {
pendingStack.push(new Set());
for (var _iterator3 = _createForOfIteratorHelperLoose(values), _step3; !(_step3 = _iterator3()).done;) {
var _step3$value = _step3.value,
atom = _step3$value[0],
valueOrPromise = _step3$value[1];
if (hasInitialValue(atom)) {
setAtomValueOrPromise(atom, valueOrPromise);
recomputeDependents(atom);
}
}
var flushed = flushPending(pendingStack.pop());
storeListenersRev2.forEach(function (l) {
return l({
type: 'restore',
flushed: flushed
});
});
}
};
}
return {
get: readAtom,
set: writeAtom,
sub: subscribeAtom
};
};
var defaultStore;
if (process.env.NODE_ENV !== 'production') {
if (typeof globalThis.__NUMBER_OF_JOTAI_INSTANCES__ === 'number') {
++globalThis.__NUMBER_OF_JOTAI_INSTANCES__;
} else {
globalThis.__NUMBER_OF_JOTAI_INSTANCES__ = 1;
}
}
var getDefaultStore = function getDefaultStore() {
if (!defaultStore) {
if (process.env.NODE_ENV !== 'production' && globalThis.__NUMBER_OF_JOTAI_INSTANCES__ !== 1) {
console.warn('Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044');
}
defaultStore = createStore();
}
return defaultStore;
};
exports.atom = atom;
exports.createStore = createStore;
exports.getDefaultStore = getDefaultStore;