jotai
Version:
👻 Primitive and flexible state management for React
557 lines (554 loc) • 21.6 kB
JavaScript
System.register([], (function (exports) {
'use strict';
return {
execute: (function () {
const isSelfAtom = (atom, a) => atom.unstable_is ? atom.unstable_is(a) : a === atom;
const hasInitialValue = (atom) => "init" in atom;
const isActuallyWritableAtom = (atom) => !!atom.write;
const isAtomStateInitialized = (atomState) => "v" in atomState || "e" in atomState;
const returnAtomValue = (atomState) => {
if ("e" in atomState) {
throw atomState.e;
}
if (!("v" in atomState)) {
throw new Error("[Bug] atom state is not initialized");
}
return atomState.v;
};
const promiseStateMap = /* @__PURE__ */ new WeakMap();
const isPendingPromise = (value) => {
var _a;
return isPromiseLike(value) && !!((_a = promiseStateMap.get(value)) == null ? void 0 : _a[0]);
};
const abortPromise = (promise) => {
const promiseState = promiseStateMap.get(promise);
if (promiseState == null ? void 0 : promiseState[0]) {
promiseState[0] = false;
promiseState[1].forEach((fn) => fn());
}
};
const registerAbortHandler = (promise, abortHandler) => {
let promiseState = promiseStateMap.get(promise);
if (!promiseState) {
promiseState = [true, /* @__PURE__ */ new Set()];
promiseStateMap.set(promise, promiseState);
const settle = () => {
promiseState[0] = false;
};
promise.then(settle, settle);
}
promiseState[1].add(abortHandler);
};
const isPromiseLike = (p) => typeof (p == null ? void 0 : p.then) === "function";
const addPendingPromiseToDependency = (atom, promise, dependencyAtomState) => {
if (!dependencyAtomState.p.has(atom)) {
dependencyAtomState.p.add(atom);
promise.then(
() => {
dependencyAtomState.p.delete(atom);
},
() => {
dependencyAtomState.p.delete(atom);
}
);
}
};
const setAtomStateValueOrPromise = (atom, valueOrPromise, ensureAtomState) => {
const atomState = ensureAtomState(atom);
const hasPrevValue = "v" in atomState;
const prevValue = atomState.v;
if (isPromiseLike(valueOrPromise)) {
for (const a of atomState.d.keys()) {
addPendingPromiseToDependency(atom, valueOrPromise, ensureAtomState(a));
}
}
atomState.v = valueOrPromise;
delete atomState.e;
if (!hasPrevValue || !Object.is(prevValue, atomState.v)) {
++atomState.n;
if (isPromiseLike(prevValue)) {
abortPromise(prevValue);
}
}
};
const getMountedOrPendingDependents = (atom, atomState, mountedMap) => {
var _a;
const dependents = /* @__PURE__ */ new Set();
for (const a of ((_a = mountedMap.get(atom)) == null ? void 0 : _a.t) || []) {
if (mountedMap.has(a)) {
dependents.add(a);
}
}
for (const atomWithPendingPromise of atomState.p) {
dependents.add(atomWithPendingPromise);
}
return dependents;
};
const createStoreHook = () => {
const callbacks = /* @__PURE__ */ new Set();
const notify = () => {
callbacks.forEach((fn) => fn());
};
notify.add = (fn) => {
callbacks.add(fn);
return () => {
callbacks.delete(fn);
};
};
return notify;
};
const createStoreHookForAtoms = () => {
const all = {};
const callbacks = /* @__PURE__ */ new WeakMap();
const notify = (atom) => {
var _a, _b;
(_a = callbacks.get(all)) == null ? void 0 : _a.forEach((fn) => fn(atom));
(_b = callbacks.get(atom)) == null ? void 0 : _b.forEach((fn) => fn());
};
notify.add = (atom, fn) => {
const key = atom || all;
const fns = (callbacks.has(key) ? callbacks : callbacks.set(key, /* @__PURE__ */ new Set())).get(key);
fns.add(fn);
return () => {
fns == null ? void 0 : fns.delete(fn);
if (!fns.size) {
callbacks.delete(key);
}
};
};
return notify;
};
const initializeStoreHooks = (storeHooks) => {
storeHooks.c || (storeHooks.c = createStoreHookForAtoms());
storeHooks.m || (storeHooks.m = createStoreHookForAtoms());
storeHooks.u || (storeHooks.u = createStoreHookForAtoms());
storeHooks.f || (storeHooks.f = createStoreHook());
return storeHooks;
};
const BUILDING_BLOCKS = Symbol();
const getBuildingBlocks = (store) => store[BUILDING_BLOCKS];
const buildStore = (atomStateMap = /* @__PURE__ */ new WeakMap(), mountedMap = /* @__PURE__ */ new WeakMap(), invalidatedAtoms = /* @__PURE__ */ new WeakMap(), changedAtoms = /* @__PURE__ */ new Set(), mountCallbacks = /* @__PURE__ */ new Set(), unmountCallbacks = /* @__PURE__ */ new Set(), storeHooks = {}, atomRead = (atom, ...params) => atom.read(...params), atomWrite = (atom, ...params) => atom.write(...params), atomOnInit = (atom, store) => {
var _a;
return (_a = atom.unstable_onInit) == null ? void 0 : _a.call(atom, store);
}, atomOnMount = (atom, setAtom) => {
var _a;
return (_a = atom.onMount) == null ? void 0 : _a.call(atom, setAtom);
}, ...buildingBlockFunctions) => {
const ensureAtomState = buildingBlockFunctions[0] || ((atom) => {
if (!atom) {
throw new Error("Atom is undefined or null");
}
let atomState = atomStateMap.get(atom);
if (!atomState) {
atomState = { d: /* @__PURE__ */ new Map(), p: /* @__PURE__ */ new Set(), n: 0 };
atomStateMap.set(atom, atomState);
atomOnInit == null ? void 0 : atomOnInit(atom, store);
}
return atomState;
});
const flushCallbacks = buildingBlockFunctions[1] || (() => {
const errors = [];
const call = (fn) => {
try {
fn();
} catch (e) {
errors.push(e);
}
};
do {
if (storeHooks.f) {
call(storeHooks.f);
}
const callbacks = /* @__PURE__ */ new Set();
const add = callbacks.add.bind(callbacks);
changedAtoms.forEach((atom) => {
var _a;
return (_a = mountedMap.get(atom)) == null ? void 0 : _a.l.forEach(add);
});
changedAtoms.clear();
unmountCallbacks.forEach(add);
unmountCallbacks.clear();
mountCallbacks.forEach(add);
mountCallbacks.clear();
callbacks.forEach(call);
if (changedAtoms.size) {
recomputeInvalidatedAtoms();
}
} while (changedAtoms.size || unmountCallbacks.size || mountCallbacks.size);
if (errors.length) {
throw new AggregateError(errors);
}
});
const recomputeInvalidatedAtoms = buildingBlockFunctions[2] || (() => {
const topSortedReversed = [];
const visiting = /* @__PURE__ */ new WeakSet();
const visited = /* @__PURE__ */ new WeakSet();
const stack = Array.from(changedAtoms);
while (stack.length) {
const a = stack[stack.length - 1];
const aState = ensureAtomState(a);
if (visited.has(a)) {
stack.pop();
continue;
}
if (visiting.has(a)) {
if (invalidatedAtoms.get(a) === aState.n) {
topSortedReversed.push([a, aState]);
} else if (invalidatedAtoms.has(a)) {
throw new Error("[Bug] invalidated atom exists");
}
visited.add(a);
stack.pop();
continue;
}
visiting.add(a);
for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) {
if (!visiting.has(d)) {
stack.push(d);
}
}
}
for (let i = topSortedReversed.length - 1; i >= 0; --i) {
const [a, aState] = topSortedReversed[i];
let hasChangedDeps = false;
for (const dep of aState.d.keys()) {
if (dep !== a && changedAtoms.has(dep)) {
hasChangedDeps = true;
break;
}
}
if (hasChangedDeps) {
readAtomState(a);
mountDependencies(a);
}
invalidatedAtoms.delete(a);
}
});
const readAtomState = buildingBlockFunctions[3] || ((atom) => {
var _a;
const atomState = ensureAtomState(atom);
if (isAtomStateInitialized(atomState)) {
if (mountedMap.has(atom) && invalidatedAtoms.get(atom) !== atomState.n) {
return atomState;
}
if (Array.from(atomState.d).every(
([a, n]) => (
// Recursively, read the atom state of the dependency, and
// check if the atom epoch number is unchanged
readAtomState(a).n === n
)
)) {
return atomState;
}
}
atomState.d.clear();
let isSync = true;
const mountDependenciesIfAsync = () => {
if (mountedMap.has(atom)) {
mountDependencies(atom);
recomputeInvalidatedAtoms();
flushCallbacks();
}
};
const getter = (a) => {
var _a2;
if (isSelfAtom(atom, a)) {
const aState2 = ensureAtomState(a);
if (!isAtomStateInitialized(aState2)) {
if (hasInitialValue(a)) {
setAtomStateValueOrPromise(a, a.init, ensureAtomState);
} else {
throw new Error("no atom init");
}
}
return returnAtomValue(aState2);
}
const aState = readAtomState(a);
try {
return returnAtomValue(aState);
} finally {
atomState.d.set(a, aState.n);
if (isPendingPromise(atomState.v)) {
addPendingPromiseToDependency(atom, atomState.v, aState);
}
(_a2 = mountedMap.get(a)) == null ? void 0 : _a2.t.add(atom);
if (!isSync) {
mountDependenciesIfAsync();
}
}
};
let controller;
let setSelf;
const options = {
get signal() {
if (!controller) {
controller = new AbortController();
}
return controller.signal;
},
get setSelf() {
if (!isActuallyWritableAtom(atom)) {
console.warn("setSelf function cannot be used with read-only atom");
}
if (!setSelf && isActuallyWritableAtom(atom)) {
setSelf = (...args) => {
if (isSync) {
console.warn("setSelf function cannot be called in sync");
}
if (!isSync) {
try {
return writeAtomState(atom, ...args);
} finally {
recomputeInvalidatedAtoms();
flushCallbacks();
}
}
};
}
return setSelf;
}
};
const prevEpochNumber = atomState.n;
try {
const valueOrPromise = atomRead(atom, getter, options);
setAtomStateValueOrPromise(atom, valueOrPromise, ensureAtomState);
if (isPromiseLike(valueOrPromise)) {
registerAbortHandler(valueOrPromise, () => controller == null ? void 0 : controller.abort());
valueOrPromise.then(
mountDependenciesIfAsync,
mountDependenciesIfAsync
);
}
return atomState;
} catch (error) {
delete atomState.v;
atomState.e = error;
++atomState.n;
return atomState;
} finally {
isSync = false;
if (prevEpochNumber !== atomState.n && invalidatedAtoms.get(atom) === prevEpochNumber) {
invalidatedAtoms.set(atom, atomState.n);
changedAtoms.add(atom);
(_a = storeHooks.c) == null ? void 0 : _a.call(storeHooks, atom);
}
}
});
const invalidateDependents = buildingBlockFunctions[4] || ((atom) => {
const stack = [atom];
while (stack.length) {
const a = stack.pop();
const aState = ensureAtomState(a);
for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) {
const dState = ensureAtomState(d);
invalidatedAtoms.set(d, dState.n);
stack.push(d);
}
}
});
const writeAtomState = buildingBlockFunctions[5] || ((atom, ...args) => {
let isSync = true;
const getter = (a) => returnAtomValue(readAtomState(a));
const setter = (a, ...args2) => {
var _a;
const aState = ensureAtomState(a);
try {
if (isSelfAtom(atom, a)) {
if (!hasInitialValue(a)) {
throw new Error("atom not writable");
}
const prevEpochNumber = aState.n;
const v = args2[0];
setAtomStateValueOrPromise(a, v, ensureAtomState);
mountDependencies(a);
if (prevEpochNumber !== aState.n) {
changedAtoms.add(a);
(_a = storeHooks.c) == null ? void 0 : _a.call(storeHooks, a);
invalidateDependents(a);
}
return void 0;
} else {
return writeAtomState(a, ...args2);
}
} finally {
if (!isSync) {
recomputeInvalidatedAtoms();
flushCallbacks();
}
}
};
try {
return atomWrite(atom, getter, setter, ...args);
} finally {
isSync = false;
}
});
const mountDependencies = buildingBlockFunctions[6] || ((atom) => {
var _a;
const atomState = ensureAtomState(atom);
const mounted = mountedMap.get(atom);
if (mounted && !isPendingPromise(atomState.v)) {
for (const [a, n] of atomState.d) {
if (!mounted.d.has(a)) {
const aState = ensureAtomState(a);
const aMounted = mountAtom(a);
aMounted.t.add(atom);
mounted.d.add(a);
if (n !== aState.n) {
changedAtoms.add(a);
(_a = storeHooks.c) == null ? void 0 : _a.call(storeHooks, a);
invalidateDependents(a);
}
}
}
for (const a of mounted.d || []) {
if (!atomState.d.has(a)) {
mounted.d.delete(a);
const aMounted = unmountAtom(a);
aMounted == null ? void 0 : aMounted.t.delete(atom);
}
}
}
});
const mountAtom = buildingBlockFunctions[7] || ((atom) => {
var _a;
const atomState = ensureAtomState(atom);
let mounted = mountedMap.get(atom);
if (!mounted) {
readAtomState(atom);
for (const a of atomState.d.keys()) {
const aMounted = mountAtom(a);
aMounted.t.add(atom);
}
mounted = {
l: /* @__PURE__ */ new Set(),
d: new Set(atomState.d.keys()),
t: /* @__PURE__ */ new Set()
};
mountedMap.set(atom, mounted);
(_a = storeHooks.m) == null ? void 0 : _a.call(storeHooks, atom);
if (isActuallyWritableAtom(atom)) {
const processOnMount = () => {
let isSync = true;
const setAtom = (...args) => {
try {
return writeAtomState(atom, ...args);
} finally {
if (!isSync) {
recomputeInvalidatedAtoms();
flushCallbacks();
}
}
};
try {
const onUnmount = atomOnMount(atom, setAtom);
if (onUnmount) {
mounted.u = () => {
isSync = true;
try {
onUnmount();
} finally {
isSync = false;
}
};
}
} finally {
isSync = false;
}
};
mountCallbacks.add(processOnMount);
}
}
return mounted;
});
const unmountAtom = buildingBlockFunctions[8] || ((atom) => {
var _a;
const atomState = ensureAtomState(atom);
let mounted = mountedMap.get(atom);
if (mounted && !mounted.l.size && !Array.from(mounted.t).some((a) => {
var _a2;
return (_a2 = mountedMap.get(a)) == null ? void 0 : _a2.d.has(atom);
})) {
if (mounted.u) {
unmountCallbacks.add(mounted.u);
}
mounted = void 0;
mountedMap.delete(atom);
(_a = storeHooks.u) == null ? void 0 : _a.call(storeHooks, atom);
for (const a of atomState.d.keys()) {
const aMounted = unmountAtom(a);
aMounted == null ? void 0 : aMounted.t.delete(atom);
}
return void 0;
}
return mounted;
});
const buildingBlocks = [
// store state
atomStateMap,
mountedMap,
invalidatedAtoms,
changedAtoms,
mountCallbacks,
unmountCallbacks,
storeHooks,
// atom intercepters
atomRead,
atomWrite,
atomOnInit,
atomOnMount,
// building-block functions
ensureAtomState,
flushCallbacks,
recomputeInvalidatedAtoms,
readAtomState,
invalidateDependents,
writeAtomState,
mountDependencies,
mountAtom,
unmountAtom
];
const store = {
get: (atom) => returnAtomValue(readAtomState(atom)),
set: (atom, ...args) => {
try {
return writeAtomState(atom, ...args);
} finally {
recomputeInvalidatedAtoms();
flushCallbacks();
}
},
sub: (atom, listener) => {
const mounted = mountAtom(atom);
const listeners = mounted.l;
listeners.add(listener);
flushCallbacks();
return () => {
listeners.delete(listener);
unmountAtom(atom);
flushCallbacks();
};
}
};
Object.defineProperty(store, BUILDING_BLOCKS, { value: buildingBlocks });
return store;
};
const INTERNAL_buildStoreRev1 = exports("INTERNAL_buildStoreRev1", buildStore);
const INTERNAL_getBuildingBlocksRev1 = exports("INTERNAL_getBuildingBlocksRev1", getBuildingBlocks);
const INTERNAL_initializeStoreHooks = exports("INTERNAL_initializeStoreHooks", initializeStoreHooks);
const INTERNAL_isSelfAtom = exports("INTERNAL_isSelfAtom", isSelfAtom);
const INTERNAL_hasInitialValue = exports("INTERNAL_hasInitialValue", hasInitialValue);
const INTERNAL_isActuallyWritableAtom = exports("INTERNAL_isActuallyWritableAtom", isActuallyWritableAtom);
const INTERNAL_isAtomStateInitialized = exports("INTERNAL_isAtomStateInitialized", isAtomStateInitialized);
const INTERNAL_returnAtomValue = exports("INTERNAL_returnAtomValue", returnAtomValue);
const INTERNAL_promiseStateMap = exports("INTERNAL_promiseStateMap", promiseStateMap);
const INTERNAL_isPendingPromise = exports("INTERNAL_isPendingPromise", isPendingPromise);
const INTERNAL_abortPromise = exports("INTERNAL_abortPromise", abortPromise);
const INTERNAL_registerAbortHandler = exports("INTERNAL_registerAbortHandler", registerAbortHandler);
const INTERNAL_isPromiseLike = exports("INTERNAL_isPromiseLike", isPromiseLike);
const INTERNAL_addPendingPromiseToDependency = exports("INTERNAL_addPendingPromiseToDependency", addPendingPromiseToDependency);
const INTERNAL_setAtomStateValueOrPromise = exports("INTERNAL_setAtomStateValueOrPromise", setAtomStateValueOrPromise);
const INTERNAL_getMountedOrPendingDependents = exports("INTERNAL_getMountedOrPendingDependents", getMountedOrPendingDependents);
})
};
}));