jotai
Version:
👻 Next gen state management that will spook you
797 lines (786 loc) • 28.1 kB
JavaScript
import { createContext, useState, useEffect, useDebugValue, useRef, createElement, useContext, useCallback, useReducer } from 'react';
const SUSPENSE_PROMISE = Symbol();
const isSuspensePromise = (promise) => !!promise[SUSPENSE_PROMISE];
const isSuspensePromiseAlreadyCancelled = (suspensePromise) => !suspensePromise[SUSPENSE_PROMISE].c;
const cancelSuspensePromise = (suspensePromise) => {
var _a, _b;
(_b = (_a = suspensePromise[SUSPENSE_PROMISE]).c) == null ? void 0 : _b.call(_a);
};
const isEqualSuspensePromise = (oldSuspensePromise, newSuspensePromise) => {
const oldOriginalPromise = oldSuspensePromise[SUSPENSE_PROMISE].o;
const newOriginalPromise = newSuspensePromise[SUSPENSE_PROMISE].o;
return oldOriginalPromise === newOriginalPromise || oldSuspensePromise === newOriginalPromise || isSuspensePromise(oldOriginalPromise) && isEqualSuspensePromise(oldOriginalPromise, newSuspensePromise);
};
const createSuspensePromise = (promise) => {
const objectToAttach = {
o: promise,
c: null
};
const suspensePromise = new Promise((resolve) => {
objectToAttach.c = () => {
objectToAttach.c = null;
resolve();
};
promise.then(objectToAttach.c, objectToAttach.c);
});
suspensePromise[SUSPENSE_PROMISE] = objectToAttach;
return suspensePromise;
};
var __defProp$1 = Object.defineProperty;
var __defProps$1 = Object.defineProperties;
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$1 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
if (__getOwnPropSymbols$1)
for (var prop of __getOwnPropSymbols$1(b)) {
if (__propIsEnum$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
}
return a;
};
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
const hasInitialValue = (atom) => "init" in atom;
const READ_ATOM = "r";
const WRITE_ATOM = "w";
const COMMIT_ATOM = "c";
const SUBSCRIBE_ATOM = "s";
const RESTORE_ATOMS = "h";
const DEV_SUBSCRIBE_STATE = "n";
const DEV_GET_MOUNTED_ATOMS = "l";
const DEV_GET_ATOM_STATE = "a";
const DEV_GET_MOUNTED = "m";
const createStore = (initialValues) => {
const committedAtomStateMap = /* @__PURE__ */ new WeakMap();
const mountedMap = /* @__PURE__ */ new WeakMap();
const pendingMap = /* @__PURE__ */ new Map();
let stateListeners;
let mountedAtoms;
if ((import.meta.env && import.meta.env.MODE) !== "production") {
stateListeners = /* @__PURE__ */ new Set();
mountedAtoms = /* @__PURE__ */ new Set();
}
if (initialValues) {
for (const [atom, value] of initialValues) {
const atomState = { v: value, r: 0, d: /* @__PURE__ */ new Map() };
if ((import.meta.env && import.meta.env.MODE) !== "production") {
Object.freeze(atomState);
if (!hasInitialValue(atom)) {
console.warn("Found initial value for derived atom which can cause unexpected behavior", atom);
}
}
committedAtomStateMap.set(atom, atomState);
}
}
const suspensePromiseCacheMap = /* @__PURE__ */ new WeakMap();
const addSuspensePromiseToCache = (version, atom, suspensePromise) => {
let cache = suspensePromiseCacheMap.get(atom);
if (!cache) {
cache = /* @__PURE__ */ new Map();
suspensePromiseCacheMap.set(atom, cache);
}
suspensePromise.then(() => {
if (cache.get(version) === suspensePromise) {
cache.delete(version);
if (!cache.size) {
suspensePromiseCacheMap.delete(atom);
}
}
});
cache.set(version, suspensePromise);
};
const cancelAllSuspensePromiseInCache = (atom) => {
const versionSet = /* @__PURE__ */ new Set();
const cache = suspensePromiseCacheMap.get(atom);
if (cache) {
suspensePromiseCacheMap.delete(atom);
cache.forEach((suspensePromise, version) => {
cancelSuspensePromise(suspensePromise);
versionSet.add(version);
});
}
return versionSet;
};
const versionedAtomStateMapMap = /* @__PURE__ */ new WeakMap();
const getVersionedAtomStateMap = (version) => {
let versionedAtomStateMap = versionedAtomStateMapMap.get(version);
if (!versionedAtomStateMap) {
versionedAtomStateMap = /* @__PURE__ */ new Map();
versionedAtomStateMapMap.set(version, versionedAtomStateMap);
}
return versionedAtomStateMap;
};
const getAtomState = (version, atom) => {
if (version) {
const versionedAtomStateMap = getVersionedAtomStateMap(version);
let atomState = versionedAtomStateMap.get(atom);
if (!atomState) {
atomState = getAtomState(version.p, atom);
if (atomState) {
if ("p" in atomState) {
atomState.p.then(() => versionedAtomStateMap.delete(atom));
}
versionedAtomStateMap.set(atom, atomState);
}
}
return atomState;
}
return committedAtomStateMap.get(atom);
};
const setAtomState = (version, atom, atomState) => {
if ((import.meta.env && import.meta.env.MODE) !== "production") {
Object.freeze(atomState);
}
if (version) {
const versionedAtomStateMap = getVersionedAtomStateMap(version);
versionedAtomStateMap.set(atom, atomState);
} else {
const prevAtomState = committedAtomStateMap.get(atom);
committedAtomStateMap.set(atom, atomState);
if (!pendingMap.has(atom)) {
pendingMap.set(atom, prevAtomState);
}
}
};
const createReadDependencies = (version, prevReadDependencies = /* @__PURE__ */ new Map(), dependencies) => {
if (!dependencies) {
return prevReadDependencies;
}
const readDependencies = /* @__PURE__ */ new Map();
let changed = false;
dependencies.forEach((atom) => {
var _a;
const revision = ((_a = getAtomState(version, atom)) == null ? void 0 : _a.r) || 0;
readDependencies.set(atom, revision);
if (prevReadDependencies.get(atom) !== revision) {
changed = true;
}
});
if (prevReadDependencies.size === readDependencies.size && !changed) {
return prevReadDependencies;
}
return readDependencies;
};
const setAtomValue = (version, atom, value, dependencies, suspensePromise) => {
const atomState = getAtomState(version, atom);
if (atomState) {
if (suspensePromise && (!("p" in atomState) || !isEqualSuspensePromise(atomState.p, suspensePromise))) {
return atomState;
}
if ("p" in atomState) {
cancelSuspensePromise(atomState.p);
}
}
const nextAtomState = {
v: value,
r: (atomState == null ? void 0 : atomState.r) || 0,
d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
};
if (!atomState || !("v" in atomState) || !Object.is(atomState.v, value)) {
++nextAtomState.r;
if (nextAtomState.d.has(atom)) {
nextAtomState.d = new Map(nextAtomState.d).set(atom, nextAtomState.r);
}
} else if (nextAtomState.d !== atomState.d && (nextAtomState.d.size !== atomState.d.size || !Array.from(nextAtomState.d.keys()).every((a) => atomState.d.has(a)))) {
Promise.resolve().then(() => {
flushPending(version);
});
}
setAtomState(version, atom, nextAtomState);
return nextAtomState;
};
const setAtomReadError = (version, atom, error, dependencies, suspensePromise) => {
const atomState = getAtomState(version, atom);
if (atomState) {
if (suspensePromise && (!("p" in atomState) || !isEqualSuspensePromise(atomState.p, suspensePromise))) {
return atomState;
}
if ("p" in atomState) {
cancelSuspensePromise(atomState.p);
}
}
const nextAtomState = {
e: error,
r: (atomState == null ? void 0 : atomState.r) || 0,
d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
};
setAtomState(version, atom, nextAtomState);
return nextAtomState;
};
const setAtomSuspensePromise = (version, atom, suspensePromise, dependencies) => {
const atomState = getAtomState(version, atom);
if (atomState && "p" in atomState) {
if (isEqualSuspensePromise(atomState.p, suspensePromise)) {
return atomState;
}
cancelSuspensePromise(atomState.p);
}
addSuspensePromiseToCache(version, atom, suspensePromise);
const nextAtomState = {
p: suspensePromise,
r: (atomState == null ? void 0 : atomState.r) || 0,
d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
};
setAtomState(version, atom, nextAtomState);
return nextAtomState;
};
const setAtomPromiseOrValue = (version, atom, promiseOrValue, dependencies) => {
if (promiseOrValue instanceof Promise) {
const suspensePromise = createSuspensePromise(promiseOrValue.then((value) => {
setAtomValue(version, atom, value, dependencies, suspensePromise);
flushPending(version);
}).catch((e) => {
if (e instanceof Promise) {
if (isSuspensePromise(e)) {
return e.then(() => {
readAtomState(version, atom, true);
});
}
return e;
}
setAtomReadError(version, atom, e, dependencies, suspensePromise);
flushPending(version);
}));
return setAtomSuspensePromise(version, atom, suspensePromise, dependencies);
}
return setAtomValue(version, atom, promiseOrValue, dependencies);
};
const setAtomInvalidated = (version, atom) => {
const atomState = getAtomState(version, atom);
if (atomState) {
if ("p" in atomState) {
cancelSuspensePromise(atomState.p);
}
const nextAtomState = __spreadProps$1(__spreadValues$1({}, atomState), {
i: atomState.r
});
setAtomState(version, atom, nextAtomState);
} else if ((import.meta.env && import.meta.env.MODE) !== "production") {
console.warn("[Bug] could not invalidate non existing atom", atom);
}
};
const readAtomState = (version, atom, force) => {
if (!force) {
const atomState = getAtomState(version, atom);
if (atomState) {
if (atomState.r !== atomState.i && "p" in atomState && !isSuspensePromiseAlreadyCancelled(atomState.p)) {
return atomState;
}
atomState.d.forEach((_, a) => {
if (a !== atom) {
if (!mountedMap.has(a)) {
readAtomState(version, a);
} else {
const aState = getAtomState(version, a);
if (aState && aState.r === aState.i) {
readAtomState(version, a);
}
}
}
});
if (Array.from(atomState.d).every(([a, r]) => {
const aState = getAtomState(version, a);
return aState && "v" in aState && aState.r === r;
})) {
return atomState;
}
}
}
const dependencies = /* @__PURE__ */ new Set();
try {
const promiseOrValue = atom.read((a) => {
dependencies.add(a);
const aState = a === atom ? getAtomState(version, a) : readAtomState(version, a);
if (aState) {
if ("e" in aState) {
throw aState.e;
}
if ("p" in aState) {
throw aState.p;
}
return aState.v;
}
if (hasInitialValue(a)) {
return a.init;
}
throw new Error("no atom init");
});
return setAtomPromiseOrValue(version, atom, promiseOrValue, dependencies);
} catch (errorOrPromise) {
if (errorOrPromise instanceof Promise) {
const suspensePromise = createSuspensePromise(errorOrPromise);
return setAtomSuspensePromise(version, atom, suspensePromise, dependencies);
}
return setAtomReadError(version, atom, errorOrPromise, dependencies);
}
};
const readAtom = (readingAtom, version) => {
const atomState = readAtomState(version, readingAtom);
return atomState;
};
const addAtom = (addingAtom) => {
let mounted = mountedMap.get(addingAtom);
if (!mounted) {
mounted = mountAtom(addingAtom);
}
return mounted;
};
const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
const delAtom = (deletingAtom) => {
const mounted = mountedMap.get(deletingAtom);
if (mounted && canUnmountAtom(deletingAtom, mounted)) {
unmountAtom(deletingAtom);
}
};
const invalidateDependents = (version, atom) => {
const mounted = mountedMap.get(atom);
mounted == null ? void 0 : mounted.t.forEach((dependent) => {
if (dependent !== atom) {
setAtomInvalidated(version, dependent);
invalidateDependents(version, dependent);
}
});
};
const writeAtomState = (version, atom, update) => {
let isSync = true;
const writeGetter = (a, options) => {
const aState = readAtomState(version, a);
if ("e" in aState) {
throw aState.e;
}
if ("p" in aState) {
if (options == null ? void 0 : options.unstable_promise) {
return aState.p.then(() => writeGetter(a, options));
}
if ((import.meta.env && import.meta.env.MODE) !== "production") {
console.info("Reading pending atom state in write operation. We throw a promise for now.", a);
}
throw aState.p;
}
if ("v" in aState) {
return aState.v;
}
if ((import.meta.env && import.meta.env.MODE) !== "production") {
console.warn("[Bug] no value found while reading atom in write operation. This is probably a bug.", a);
}
throw new Error("no value found");
};
const setter = (a, v) => {
let promiseOrVoid2;
if (a === atom) {
if (!hasInitialValue(a)) {
throw new Error("atom not writable");
}
const versionSet = cancelAllSuspensePromiseInCache(a);
versionSet.forEach((cancelledVersion) => {
if (cancelledVersion !== version) {
setAtomPromiseOrValue(cancelledVersion, a, v);
}
});
setAtomPromiseOrValue(version, a, v);
invalidateDependents(version, a);
} else {
promiseOrVoid2 = writeAtomState(version, a, v);
}
if (!isSync) {
flushPending(version);
}
return promiseOrVoid2;
};
const promiseOrVoid = atom.write(writeGetter, setter, update);
isSync = false;
version = void 0;
return promiseOrVoid;
};
const writeAtom = (writingAtom, update, version) => {
const promiseOrVoid = writeAtomState(version, writingAtom, update);
flushPending(version);
return promiseOrVoid;
};
const isActuallyWritableAtom = (atom) => !!atom.write;
const mountAtom = (atom, initialDependent) => {
const mounted = {
t: new Set(initialDependent && [initialDependent]),
l: /* @__PURE__ */ new Set()
};
mountedMap.set(atom, mounted);
if ((import.meta.env && import.meta.env.MODE) !== "production") {
mountedAtoms.add(atom);
}
const atomState = readAtomState(void 0, atom);
atomState.d.forEach((_, a) => {
const aMounted = mountedMap.get(a);
if (aMounted) {
aMounted.t.add(atom);
} else {
if (a !== atom) {
mountAtom(a, atom);
}
}
});
if (isActuallyWritableAtom(atom) && atom.onMount) {
const setAtom = (update) => writeAtom(atom, update);
const onUnmount = atom.onMount(setAtom);
if (onUnmount) {
mounted.u = onUnmount;
}
}
return mounted;
};
const unmountAtom = (atom) => {
var _a;
const onUnmount = (_a = mountedMap.get(atom)) == null ? void 0 : _a.u;
if (onUnmount) {
onUnmount();
}
mountedMap.delete(atom);
if ((import.meta.env && import.meta.env.MODE) !== "production") {
mountedAtoms.delete(atom);
}
const atomState = getAtomState(void 0, atom);
if (atomState) {
atomState.d.forEach((_, a) => {
if (a !== atom) {
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.delete(atom);
if (canUnmountAtom(a, mounted)) {
unmountAtom(a);
}
}
}
});
} else if ((import.meta.env && import.meta.env.MODE) !== "production") {
console.warn("[Bug] could not find atom state to unmount", atom);
}
};
const mountDependencies = (atom, atomState, prevReadDependencies) => {
const dependencies = new Set(atomState.d.keys());
prevReadDependencies == null ? void 0 : prevReadDependencies.forEach((_, a) => {
if (dependencies.has(a)) {
dependencies.delete(a);
return;
}
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.delete(atom);
if (canUnmountAtom(a, mounted)) {
unmountAtom(a);
}
}
});
dependencies.forEach((a) => {
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.add(atom);
} else if (mountedMap.has(atom)) {
mountAtom(a, atom);
}
});
};
const flushPending = (version) => {
if (version) {
const versionedAtomStateMap = getVersionedAtomStateMap(version);
versionedAtomStateMap.forEach((atomState, atom) => {
if (atomState !== committedAtomStateMap.get(atom)) {
const mounted = mountedMap.get(atom);
mounted == null ? void 0 : mounted.l.forEach((listener) => listener(version));
}
});
return;
}
while (pendingMap.size) {
const pending = Array.from(pendingMap);
pendingMap.clear();
pending.forEach(([atom, prevAtomState]) => {
const atomState = getAtomState(void 0, atom);
if (atomState && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
const mounted = mountedMap.get(atom);
mounted == null ? void 0 : mounted.l.forEach((listener) => listener());
});
}
if ((import.meta.env && import.meta.env.MODE) !== "production") {
stateListeners.forEach((l) => l());
}
};
const commitVersionedAtomStateMap = (version) => {
const versionedAtomStateMap = getVersionedAtomStateMap(version);
versionedAtomStateMap.forEach((atomState, atom) => {
const prevAtomState = committedAtomStateMap.get(atom);
if (atomState.r > ((prevAtomState == null ? void 0 : prevAtomState.r) || 0) || "v" in atomState && atomState.r === (prevAtomState == null ? void 0 : prevAtomState.r) && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
committedAtomStateMap.set(atom, atomState);
if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
}
});
};
const commitAtom = (_atom, version) => {
if (version) {
commitVersionedAtomStateMap(version);
}
flushPending(void 0);
};
const subscribeAtom = (atom, callback) => {
const mounted = addAtom(atom);
const listeners = mounted.l;
listeners.add(callback);
return () => {
listeners.delete(callback);
delAtom(atom);
};
};
const restoreAtoms = (values, version) => {
for (const [atom, value] of values) {
if (hasInitialValue(atom)) {
setAtomPromiseOrValue(version, atom, value);
invalidateDependents(version, atom);
}
}
flushPending(version);
};
if ((import.meta.env && import.meta.env.MODE) !== "production") {
return {
[READ_ATOM]: readAtom,
[WRITE_ATOM]: writeAtom,
[COMMIT_ATOM]: commitAtom,
[SUBSCRIBE_ATOM]: subscribeAtom,
[RESTORE_ATOMS]: restoreAtoms,
[DEV_SUBSCRIBE_STATE]: (l) => {
stateListeners.add(l);
return () => {
stateListeners.delete(l);
};
},
[DEV_GET_MOUNTED_ATOMS]: () => mountedAtoms.values(),
[DEV_GET_ATOM_STATE]: (a) => committedAtomStateMap.get(a),
[DEV_GET_MOUNTED]: (a) => mountedMap.get(a)
};
}
return {
[READ_ATOM]: readAtom,
[WRITE_ATOM]: writeAtom,
[COMMIT_ATOM]: commitAtom,
[SUBSCRIBE_ATOM]: subscribeAtom,
[RESTORE_ATOMS]: restoreAtoms
};
};
const createStoreForExport = (initialValues) => {
const store = createStore(initialValues);
const get = (atom) => {
const atomState = store[READ_ATOM](atom);
if ("e" in atomState) {
throw atomState.e;
}
if ("p" in atomState) {
return void 0;
}
return atomState.v;
};
const asyncGet = (atom) => new Promise((resolve, reject) => {
const atomState = store[READ_ATOM](atom);
if ("e" in atomState) {
reject(atomState.e);
} else if ("p" in atomState) {
resolve(atomState.p.then(() => asyncGet(atom)));
} else {
resolve(atomState.v);
}
});
const set = (atom, update) => store[WRITE_ATOM](atom, update);
const sub = (atom, callback) => store[SUBSCRIBE_ATOM](atom, callback);
return {
get,
asyncGet,
set,
sub,
SECRET_INTERNAL_store: store
};
};
const createScopeContainer = (initialValues, unstable_createStore) => {
const store = unstable_createStore ? unstable_createStore(initialValues).SECRET_INTERNAL_store : createStore(initialValues);
return { s: store };
};
const ScopeContextMap = /* @__PURE__ */ new Map();
const getScopeContext = (scope) => {
if (!ScopeContextMap.has(scope)) {
ScopeContextMap.set(scope, createContext(createScopeContainer()));
}
return ScopeContextMap.get(scope);
};
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const atomToPrintable = (atom) => atom.debugLabel || atom.toString();
const stateToPrintable = ([store, atoms]) => Object.fromEntries(atoms.flatMap((atom) => {
var _a, _b;
const mounted = (_a = store[DEV_GET_MOUNTED]) == null ? void 0 : _a.call(store, atom);
if (!mounted) {
return [];
}
const dependents = mounted.t;
const atomState = ((_b = store[DEV_GET_ATOM_STATE]) == null ? void 0 : _b.call(store, atom)) || {};
return [
[
atomToPrintable(atom),
__spreadProps(__spreadValues(__spreadValues(__spreadValues({}, "e" in atomState && { error: atomState.e }), "p" in atomState && { promise: atomState.p }), "v" in atomState && { value: atomState.v }), {
dependents: Array.from(dependents).map(atomToPrintable)
})
]
];
}));
const useDebugState = (scopeContainer) => {
const { s: store } = scopeContainer;
const [atoms, setAtoms] = useState([]);
useEffect(() => {
var _a;
const callback = () => {
var _a2;
setAtoms(Array.from(((_a2 = store[DEV_GET_MOUNTED_ATOMS]) == null ? void 0 : _a2.call(store)) || []));
};
const unsubscribe = (_a = store[DEV_SUBSCRIBE_STATE]) == null ? void 0 : _a.call(store, callback);
callback();
return unsubscribe;
}, [store]);
useDebugValue([store, atoms], stateToPrintable);
};
const Provider = ({
children,
initialValues,
scope,
unstable_createStore,
unstable_enableVersionedWrite
}) => {
const [version, setVersion] = useState();
useEffect(() => {
if (version) {
scopeContainerRef.current.s[COMMIT_ATOM](null, version);
delete version.p;
}
}, [version]);
const scopeContainerRef = useRef();
if (!scopeContainerRef.current) {
scopeContainerRef.current = createScopeContainer(initialValues, unstable_createStore);
if (unstable_enableVersionedWrite) {
scopeContainerRef.current.w = (write) => {
setVersion((parentVersion) => {
const nextVersion = parentVersion ? { p: parentVersion } : {};
write(nextVersion);
return nextVersion;
});
};
}
}
if ((import.meta.env && import.meta.env.MODE) !== "production" && !unstable_enableVersionedWrite) {
useDebugState(scopeContainerRef.current);
}
const ScopeContainerContext = getScopeContext(scope);
return createElement(ScopeContainerContext.Provider, {
value: scopeContainerRef.current
}, children);
};
let keyCount = 0;
function atom(read, write) {
const key = `atom${++keyCount}`;
const config = {
toString: () => key
};
if (typeof read === "function") {
config.read = read;
} else {
config.init = read;
config.read = (get) => get(config);
config.write = (get, set, update) => set(config, typeof update === "function" ? update(get(config)) : update);
}
if (write) {
config.write = write;
}
return config;
}
function useAtomValue(atom, scope) {
const ScopeContext = getScopeContext(scope);
const { s: store } = useContext(ScopeContext);
const getAtomValue = useCallback((version2) => {
const atomState = store[READ_ATOM](atom, version2);
if ("e" in atomState) {
throw atomState.e;
}
if ("p" in atomState) {
throw atomState.p;
}
if ("v" in atomState) {
return atomState.v;
}
throw new Error("no atom value");
}, [store, atom]);
const [[version, value, atomFromUseReducer], rerenderIfChanged] = useReducer(useCallback((prev, nextVersion) => {
const nextValue = getAtomValue(nextVersion);
if (Object.is(prev[1], nextValue) && prev[2] === atom) {
return prev;
}
return [nextVersion, nextValue, atom];
}, [getAtomValue, atom]), void 0, () => {
const initialVersion = void 0;
const initialValue = getAtomValue(initialVersion);
return [initialVersion, initialValue, atom];
});
if (atomFromUseReducer !== atom) {
rerenderIfChanged(void 0);
}
useEffect(() => {
const unsubscribe = store[SUBSCRIBE_ATOM](atom, rerenderIfChanged);
rerenderIfChanged(void 0);
return unsubscribe;
}, [store, atom]);
useEffect(() => {
store[COMMIT_ATOM](atom, version);
});
useDebugValue(value);
return value;
}
function useSetAtom(atom, scope) {
const ScopeContext = getScopeContext(scope);
const { s: store, w: versionedWrite } = useContext(ScopeContext);
const setAtom = useCallback((update) => {
if ((import.meta.env && import.meta.env.MODE) !== "production" && !("write" in atom)) {
throw new Error("not writable atom");
}
const write = (version) => store[WRITE_ATOM](atom, update, version);
return versionedWrite ? versionedWrite(write) : write();
}, [store, versionedWrite, atom]);
return setAtom;
}
function useAtom(atom, scope) {
if ("scope" in atom) {
console.warn("atom.scope is deprecated. Please do useAtom(atom, scope) instead.");
scope = atom.scope;
}
return [
useAtomValue(atom, scope),
useSetAtom(atom, scope)
];
}
export { Provider, getScopeContext as SECRET_INTERNAL_getScopeContext, atom, createStoreForExport as unstable_createStore, useAtom, useAtomValue, useSetAtom };