jotai
Version:
👻 Primitive and flexible state management for React
661 lines (656 loc) • 21.8 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 = 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 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 '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 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 pendingMap = new Map();
var storeListenersRev1;
var storeListenersRev2;
var mountedAtoms;
if (process.env.NODE_ENV !== 'production') {
storeListenersRev1 = new Set();
storeListenersRev2 = 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, nextDependencies) {
var dependencies = new Map();
var changed = false;
nextDependencies.forEach(function (aState, a) {
if (!aState && a === atom) {
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) {
var prevAtomState = getAtomState(atom);
var nextAtomState = {
d: (prevAtomState == null ? void 0 : prevAtomState.d) || new Map(),
v: value
};
if (nextDependencies) {
updateDependencies(atom, nextAtomState, nextDependencies);
}
if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
if (prevAtomState && 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 promise = new Promise(function (resolve, reject) {
var settled = false;
valueOrPromise.then(function (v) {
if (!settled) {
settled = true;
var prevAtomState = getAtomState(atom);
var nextAtomState = setAtomValue(atom, promise, nextDependencies);
resolvePromise(promise, v);
resolve(v);
if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) {
mountDependencies(atom, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
}
}, function (e) {
if (!settled) {
settled = true;
var prevAtomState = getAtomState(atom);
var nextAtomState = setAtomValue(atom, promise, nextDependencies);
rejectPromise(promise, e);
reject(e);
if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) {
mountDependencies(atom, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
}
});
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 ? void 0 : abortPromise();
});
return setAtomValue(atom, promise, nextDependencies);
}
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 (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
setAtomState(atom, nextAtomState);
return nextAtomState;
};
var readAtomState = function readAtomState(atom) {
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 nextDependencies = new Map();
var isSync = true;
var getter = function getter(a) {
if (a === atom) {
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 dependencyMap = new Map();
var dirtyMap = new WeakMap();
var loop1 = function loop1(a) {
var mounted = mountedMap.get(a);
mounted == null ? void 0 : mounted.t.forEach(function (dependent) {
if (dependent !== a) {
dependencyMap.set(dependent, (dependencyMap.get(dependent) || new Set()).add(a));
dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1);
loop1(dependent);
}
});
};
loop1(atom);
var loop2 = function loop2(a) {
var mounted = mountedMap.get(a);
mounted == null ? void 0 : mounted.t.forEach(function (dependent) {
if (dependent !== a) {
var dirtyCount = dirtyMap.get(dependent);
if (dirtyCount) {
dirtyMap.set(dependent, --dirtyCount);
}
if (!dirtyCount) {
var _dependencyMap$get;
var isChanged = !!((_dependencyMap$get = dependencyMap.get(dependent)) != null && _dependencyMap$get.size);
if (isChanged) {
var prevAtomState = getAtomState(dependent);
var nextAtomState = readAtomState(dependent);
isChanged = !prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState);
}
if (!isChanged) {
dependencyMap.forEach(function (s) {
return s.delete(dependent);
});
}
}
loop2(dependent);
}
});
};
loop2(atom);
};
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 = setAtomValueOrPromise(a, args[0]);
if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
recomputeDependents(a);
}
} else {
r = writeAtomState.apply(void 0, [a].concat(args));
}
if (!isSync) {
var flushed = flushPending();
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) {
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();
if (process.env.NODE_ENV !== 'production') {
storeListenersRev2.forEach(function (l) {
return l({
type: 'write',
flushed: flushed
});
});
}
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() {
var flushed;
if (process.env.NODE_ENV !== 'production') {
flushed = new Set();
}
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);
if (mounted && !(prevAtomState && !hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
mounted.l.forEach(function (listener) {
return listener();
});
if (process.env.NODE_ENV !== 'production') {
flushed.add(atom);
}
}
} else if (process.env.NODE_ENV !== 'production') {
console.warn('[Bug] no atom state to flush');
}
});
}
if (process.env.NODE_ENV !== 'production') {
storeListenersRev1.forEach(function (l) {
return l('state');
});
return flushed;
}
};
var subscribeAtom = function subscribeAtom(atom, listener) {
var mounted = addAtom(atom);
var flushed = flushPending();
var listeners = mounted.l;
listeners.add(listener);
if (process.env.NODE_ENV !== 'production') {
storeListenersRev1.forEach(function (l) {
return l('sub');
});
storeListenersRev2.forEach(function (l) {
return l({
type: 'sub',
flushed: flushed
});
});
}
return function () {
listeners.delete(listener);
delAtom(atom);
if (process.env.NODE_ENV !== 'production') {
storeListenersRev1.forEach(function (l) {
return l('unsub');
});
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 (l, rev) {
if (rev !== 2) {
console.warn('The current StoreListener revision is 2. The older ones are deprecated.');
storeListenersRev1.add(l);
return function () {
storeListenersRev1.delete(l);
};
}
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) {
for (var _iterator = _createForOfIteratorHelperLoose(values), _step; !(_step = _iterator()).done;) {
var _step$value = _step.value,
atom = _step$value[0],
valueOrPromise = _step$value[1];
if (hasInitialValue(atom)) {
setAtomValueOrPromise(atom, valueOrPromise);
recomputeDependents(atom);
}
}
var flushed = flushPending();
storeListenersRev2.forEach(function (l) {
return l({
type: 'restore',
flushed: flushed
});
});
}
};
}
return {
get: readAtom,
set: writeAtom,
sub: subscribeAtom
};
};
var defaultStore;
var getDefaultStore = function getDefaultStore() {
if (!defaultStore) {
defaultStore = createStore();
}
return defaultStore;
};
exports.atom = atom;
exports.createStore = createStore;
exports.getDefaultStore = getDefaultStore;
;