UNPKG

25.6 kBJavaScriptView Raw
1import { createContext, useState, useEffect, useRef, createElement, useContext, useReducer, useDebugValue, useCallback } from 'react';
2
3const SUSPENSE_PROMISE = Symbol();
4const isSuspensePromise = (promise) => !!promise[SUSPENSE_PROMISE];
5const isSuspensePromiseAlreadyCancelled = (suspensePromise) => !suspensePromise[SUSPENSE_PROMISE].c;
6const cancelSuspensePromise = (suspensePromise) => {
7 var _a, _b;
8 (_b = (_a = suspensePromise[SUSPENSE_PROMISE]).c) == null ? void 0 : _b.call(_a);
9};
10const isEqualSuspensePromise = (oldSuspensePromise, newSuspensePromise) => {
11 const oldOriginalPromise = oldSuspensePromise[SUSPENSE_PROMISE].o;
12 const newOriginalPromise = newSuspensePromise[SUSPENSE_PROMISE].o;
13 return oldOriginalPromise === newOriginalPromise || oldSuspensePromise === newOriginalPromise || isSuspensePromise(oldOriginalPromise) && isEqualSuspensePromise(oldOriginalPromise, newSuspensePromise);
14};
15const createSuspensePromise = (promise) => {
16 const objectToAttach = {
17 o: promise,
18 c: null
19 };
20 const suspensePromise = new Promise((resolve) => {
21 objectToAttach.c = () => {
22 objectToAttach.c = null;
23 resolve();
24 };
25 promise.then(objectToAttach.c, objectToAttach.c);
26 });
27 suspensePromise[SUSPENSE_PROMISE] = objectToAttach;
28 return suspensePromise;
29};
30
31const hasInitialValue = (atom) => "init" in atom;
32const READ_ATOM = "r";
33const WRITE_ATOM = "w";
34const COMMIT_ATOM = "c";
35const SUBSCRIBE_ATOM = "s";
36const RESTORE_ATOMS = "h";
37const DEV_SUBSCRIBE_STATE = "n";
38const DEV_GET_MOUNTED_ATOMS = "l";
39const DEV_GET_ATOM_STATE = "a";
40const DEV_GET_MOUNTED = "m";
41const createStore = (initialValues) => {
42 const committedAtomStateMap = /* @__PURE__ */ new WeakMap();
43 const mountedMap = /* @__PURE__ */ new WeakMap();
44 const pendingMap = /* @__PURE__ */ new Map();
45 let stateListeners;
46 let mountedAtoms;
47 if ((import.meta.env && import.meta.env.MODE) !== "production") {
48 stateListeners = /* @__PURE__ */ new Set();
49 mountedAtoms = /* @__PURE__ */ new Set();
50 }
51 if (initialValues) {
52 for (const [atom, value] of initialValues) {
53 const atomState = { v: value, r: 0, d: /* @__PURE__ */ new Map() };
54 if ((import.meta.env && import.meta.env.MODE) !== "production") {
55 Object.freeze(atomState);
56 if (!hasInitialValue(atom)) {
57 console.warn("Found initial value for derived atom which can cause unexpected behavior", atom);
58 }
59 }
60 committedAtomStateMap.set(atom, atomState);
61 }
62 }
63 const suspensePromiseCacheMap = /* @__PURE__ */ new WeakMap();
64 const addSuspensePromiseToCache = (version, atom, suspensePromise) => {
65 let cache = suspensePromiseCacheMap.get(atom);
66 if (!cache) {
67 cache = /* @__PURE__ */ new Map();
68 suspensePromiseCacheMap.set(atom, cache);
69 }
70 suspensePromise.then(() => {
71 if (cache.get(version) === suspensePromise) {
72 cache.delete(version);
73 if (!cache.size) {
74 suspensePromiseCacheMap.delete(atom);
75 }
76 }
77 });
78 cache.set(version, suspensePromise);
79 };
80 const cancelAllSuspensePromiseInCache = (atom) => {
81 const versionSet = /* @__PURE__ */ new Set();
82 const cache = suspensePromiseCacheMap.get(atom);
83 if (cache) {
84 suspensePromiseCacheMap.delete(atom);
85 cache.forEach((suspensePromise, version) => {
86 cancelSuspensePromise(suspensePromise);
87 versionSet.add(version);
88 });
89 }
90 return versionSet;
91 };
92 const versionedAtomStateMapMap = /* @__PURE__ */ new WeakMap();
93 const getVersionedAtomStateMap = (version) => {
94 let versionedAtomStateMap = versionedAtomStateMapMap.get(version);
95 if (!versionedAtomStateMap) {
96 versionedAtomStateMap = /* @__PURE__ */ new Map();
97 versionedAtomStateMapMap.set(version, versionedAtomStateMap);
98 }
99 return versionedAtomStateMap;
100 };
101 const getAtomState = (version, atom) => {
102 if (version) {
103 const versionedAtomStateMap = getVersionedAtomStateMap(version);
104 let atomState = versionedAtomStateMap.get(atom);
105 if (!atomState) {
106 atomState = getAtomState(version.p, atom);
107 if (atomState) {
108 versionedAtomStateMap.set(atom, atomState);
109 }
110 }
111 return atomState;
112 }
113 return committedAtomStateMap.get(atom);
114 };
115 const setAtomState = (version, atom, atomState) => {
116 if ((import.meta.env && import.meta.env.MODE) !== "production") {
117 Object.freeze(atomState);
118 }
119 if (version) {
120 const versionedAtomStateMap = getVersionedAtomStateMap(version);
121 versionedAtomStateMap.set(atom, atomState);
122 } else {
123 const prevAtomState = committedAtomStateMap.get(atom);
124 committedAtomStateMap.set(atom, atomState);
125 if (!pendingMap.has(atom)) {
126 pendingMap.set(atom, prevAtomState);
127 }
128 }
129 };
130 const createReadDependencies = (version, prevReadDependencies = /* @__PURE__ */ new Map(), dependencies) => {
131 if (!dependencies) {
132 return prevReadDependencies;
133 }
134 const readDependencies = /* @__PURE__ */ new Map();
135 let changed = false;
136 dependencies.forEach((atom) => {
137 var _a;
138 const revision = ((_a = getAtomState(version, atom)) == null ? void 0 : _a.r) || 0;
139 readDependencies.set(atom, revision);
140 if (prevReadDependencies.get(atom) !== revision) {
141 changed = true;
142 }
143 });
144 if (prevReadDependencies.size === readDependencies.size && !changed) {
145 return prevReadDependencies;
146 }
147 return readDependencies;
148 };
149 const setAtomValue = (version, atom, value, dependencies, suspensePromise) => {
150 const atomState = getAtomState(version, atom);
151 if (atomState) {
152 if (suspensePromise && (!("p" in atomState) || !isEqualSuspensePromise(atomState.p, suspensePromise))) {
153 return atomState;
154 }
155 if ("p" in atomState) {
156 cancelSuspensePromise(atomState.p);
157 }
158 }
159 const nextAtomState = {
160 v: value,
161 r: (atomState == null ? void 0 : atomState.r) || 0,
162 d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
163 };
164 let changed = false;
165 if (!atomState || !("v" in atomState) || !Object.is(atomState.v, value)) {
166 changed = true;
167 ++nextAtomState.r;
168 if (nextAtomState.d.has(atom)) {
169 nextAtomState.d = new Map(nextAtomState.d).set(atom, nextAtomState.r);
170 }
171 } else if ("i" in atomState || nextAtomState.d !== atomState.d && (nextAtomState.d.size !== atomState.d.size || !Array.from(nextAtomState.d.keys()).every((a) => atomState.d.has(a)))) {
172 changed = true;
173 Promise.resolve().then(() => {
174 flushPending(version);
175 });
176 }
177 if (atomState && !changed) {
178 return atomState;
179 }
180 setAtomState(version, atom, nextAtomState);
181 return nextAtomState;
182 };
183 const setAtomReadError = (version, atom, error, dependencies, suspensePromise) => {
184 const atomState = getAtomState(version, atom);
185 if (atomState) {
186 if (suspensePromise && (!("p" in atomState) || !isEqualSuspensePromise(atomState.p, suspensePromise))) {
187 return atomState;
188 }
189 if ("p" in atomState) {
190 cancelSuspensePromise(atomState.p);
191 }
192 }
193 const nextAtomState = {
194 e: error,
195 r: (atomState == null ? void 0 : atomState.r) || 0,
196 d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
197 };
198 setAtomState(version, atom, nextAtomState);
199 return nextAtomState;
200 };
201 const setAtomSuspensePromise = (version, atom, suspensePromise, dependencies) => {
202 const atomState = getAtomState(version, atom);
203 if (atomState && "p" in atomState) {
204 if (isEqualSuspensePromise(atomState.p, suspensePromise)) {
205 return atomState;
206 }
207 cancelSuspensePromise(atomState.p);
208 }
209 addSuspensePromiseToCache(version, atom, suspensePromise);
210 const nextAtomState = {
211 p: suspensePromise,
212 r: (atomState == null ? void 0 : atomState.r) || 0,
213 d: createReadDependencies(version, atomState == null ? void 0 : atomState.d, dependencies)
214 };
215 setAtomState(version, atom, nextAtomState);
216 return nextAtomState;
217 };
218 const setAtomPromiseOrValue = (version, atom, promiseOrValue, dependencies) => {
219 if (promiseOrValue instanceof Promise) {
220 const suspensePromise = createSuspensePromise(promiseOrValue.then((value) => {
221 setAtomValue(version, atom, value, dependencies, suspensePromise);
222 }).catch((e) => {
223 if (e instanceof Promise) {
224 if (isSuspensePromise(e)) {
225 return e.then(() => {
226 readAtomState(version, atom, true);
227 });
228 }
229 return e;
230 }
231 setAtomReadError(version, atom, e, dependencies, suspensePromise);
232 }));
233 return setAtomSuspensePromise(version, atom, suspensePromise, dependencies);
234 }
235 return setAtomValue(version, atom, promiseOrValue, dependencies);
236 };
237 const setAtomInvalidated = (version, atom) => {
238 const atomState = getAtomState(version, atom);
239 if (atomState) {
240 const nextAtomState = {
241 ...atomState,
242 i: atomState.r
243 };
244 setAtomState(version, atom, nextAtomState);
245 } else if ((import.meta.env && import.meta.env.MODE) !== "production") {
246 console.warn("[Bug] could not invalidate non existing atom", atom);
247 }
248 };
249 const readAtomState = (version, atom, force) => {
250 if (!force) {
251 const atomState = getAtomState(version, atom);
252 if (atomState) {
253 if (atomState.r !== atomState.i && "p" in atomState && !isSuspensePromiseAlreadyCancelled(atomState.p)) {
254 return atomState;
255 }
256 atomState.d.forEach((_, a) => {
257 if (a !== atom) {
258 if (!mountedMap.has(a)) {
259 readAtomState(version, a);
260 } else {
261 const aState = getAtomState(version, a);
262 if (aState && aState.r === aState.i) {
263 readAtomState(version, a);
264 }
265 }
266 }
267 });
268 if (Array.from(atomState.d).every(([a, r]) => {
269 const aState = getAtomState(version, a);
270 return aState && "v" in aState && aState.r === r;
271 })) {
272 return atomState;
273 }
274 }
275 }
276 const dependencies = /* @__PURE__ */ new Set();
277 try {
278 const promiseOrValue = atom.read((a) => {
279 dependencies.add(a);
280 const aState = a === atom ? getAtomState(version, a) : readAtomState(version, a);
281 if (aState) {
282 if ("e" in aState) {
283 throw aState.e;
284 }
285 if ("p" in aState) {
286 throw aState.p;
287 }
288 return aState.v;
289 }
290 if (hasInitialValue(a)) {
291 return a.init;
292 }
293 throw new Error("no atom init");
294 });
295 return setAtomPromiseOrValue(version, atom, promiseOrValue, dependencies);
296 } catch (errorOrPromise) {
297 if (errorOrPromise instanceof Promise) {
298 const suspensePromise = createSuspensePromise(errorOrPromise);
299 return setAtomSuspensePromise(version, atom, suspensePromise, dependencies);
300 }
301 return setAtomReadError(version, atom, errorOrPromise, dependencies);
302 }
303 };
304 const readAtom = (readingAtom, version) => {
305 const atomState = readAtomState(version, readingAtom);
306 return atomState;
307 };
308 const addAtom = (version, addingAtom) => {
309 let mounted = mountedMap.get(addingAtom);
310 if (!mounted) {
311 mounted = mountAtom(version, addingAtom);
312 }
313 return mounted;
314 };
315 const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
316 const delAtom = (version, deletingAtom) => {
317 const mounted = mountedMap.get(deletingAtom);
318 if (mounted && canUnmountAtom(deletingAtom, mounted)) {
319 unmountAtom(version, deletingAtom);
320 }
321 };
322 const invalidateDependents = (version, atom) => {
323 const mounted = mountedMap.get(atom);
324 mounted == null ? void 0 : mounted.t.forEach((dependent) => {
325 if (dependent !== atom) {
326 setAtomInvalidated(version, dependent);
327 invalidateDependents(version, dependent);
328 }
329 });
330 };
331 const writeAtomState = (version, atom, update) => {
332 let isSync = true;
333 const writeGetter = (a, options) => {
334 const aState = readAtomState(version, a);
335 if ("e" in aState) {
336 throw aState.e;
337 }
338 if ("p" in aState) {
339 if (options == null ? void 0 : options.unstable_promise) {
340 return aState.p.then(() => writeGetter(a, options));
341 }
342 if ((import.meta.env && import.meta.env.MODE) !== "production") {
343 console.info("Reading pending atom state in write operation. We throw a promise for now.", a);
344 }
345 throw aState.p;
346 }
347 if ("v" in aState) {
348 return aState.v;
349 }
350 if ((import.meta.env && import.meta.env.MODE) !== "production") {
351 console.warn("[Bug] no value found while reading atom in write operation. This is probably a bug.", a);
352 }
353 throw new Error("no value found");
354 };
355 const setter = (a, v) => {
356 let promiseOrVoid2;
357 if (a === atom) {
358 if (!hasInitialValue(a)) {
359 throw new Error("atom not writable");
360 }
361 const versionSet = cancelAllSuspensePromiseInCache(a);
362 versionSet.forEach((cancelledVersion) => {
363 if (cancelledVersion !== version) {
364 setAtomPromiseOrValue(cancelledVersion, a, v);
365 }
366 });
367 const prevAtomState = getAtomState(version, a);
368 const nextAtomState = setAtomPromiseOrValue(version, a, v);
369 if (prevAtomState !== nextAtomState) {
370 invalidateDependents(version, a);
371 }
372 } else {
373 promiseOrVoid2 = writeAtomState(version, a, v);
374 }
375 if (!isSync) {
376 flushPending(version);
377 }
378 return promiseOrVoid2;
379 };
380 const promiseOrVoid = atom.write(writeGetter, setter, update);
381 isSync = false;
382 return promiseOrVoid;
383 };
384 const writeAtom = (writingAtom, update, version) => {
385 const promiseOrVoid = writeAtomState(version, writingAtom, update);
386 flushPending(version);
387 return promiseOrVoid;
388 };
389 const isActuallyWritableAtom = (atom) => !!atom.write;
390 const mountAtom = (version, atom, initialDependent) => {
391 const mounted = {
392 t: new Set(initialDependent && [initialDependent]),
393 l: /* @__PURE__ */ new Set()
394 };
395 mountedMap.set(atom, mounted);
396 if ((import.meta.env && import.meta.env.MODE) !== "production") {
397 mountedAtoms.add(atom);
398 }
399 const atomState = readAtomState(void 0, atom);
400 atomState.d.forEach((_, a) => {
401 const aMounted = mountedMap.get(a);
402 if (aMounted) {
403 aMounted.t.add(atom);
404 } else {
405 if (a !== atom) {
406 mountAtom(version, a, atom);
407 }
408 }
409 });
410 if (isActuallyWritableAtom(atom) && atom.onMount) {
411 const setAtom = (update) => writeAtom(atom, update, version);
412 const onUnmount = atom.onMount(setAtom);
413 version = void 0;
414 if (onUnmount) {
415 mounted.u = onUnmount;
416 }
417 }
418 return mounted;
419 };
420 const unmountAtom = (version, atom) => {
421 var _a;
422 const onUnmount = (_a = mountedMap.get(atom)) == null ? void 0 : _a.u;
423 if (onUnmount) {
424 onUnmount();
425 }
426 mountedMap.delete(atom);
427 if ((import.meta.env && import.meta.env.MODE) !== "production") {
428 mountedAtoms.delete(atom);
429 }
430 const atomState = getAtomState(version, atom);
431 if (atomState) {
432 atomState.d.forEach((_, a) => {
433 if (a !== atom) {
434 const mounted = mountedMap.get(a);
435 if (mounted) {
436 mounted.t.delete(atom);
437 if (canUnmountAtom(a, mounted)) {
438 unmountAtom(version, a);
439 }
440 }
441 }
442 });
443 } else if ((import.meta.env && import.meta.env.MODE) !== "production") {
444 console.warn("[Bug] could not find atom state to unmount", atom);
445 }
446 };
447 const mountDependencies = (version, atom, atomState, prevReadDependencies) => {
448 const dependencies = new Set(atomState.d.keys());
449 prevReadDependencies == null ? void 0 : prevReadDependencies.forEach((_, a) => {
450 if (dependencies.has(a)) {
451 dependencies.delete(a);
452 return;
453 }
454 const mounted = mountedMap.get(a);
455 if (mounted) {
456 mounted.t.delete(atom);
457 if (canUnmountAtom(a, mounted)) {
458 unmountAtom(version, a);
459 }
460 }
461 });
462 dependencies.forEach((a) => {
463 const mounted = mountedMap.get(a);
464 if (mounted) {
465 mounted.t.add(atom);
466 } else if (mountedMap.has(atom)) {
467 mountAtom(version, a, atom);
468 }
469 });
470 };
471 const flushPending = (version) => {
472 if (version) {
473 const versionedAtomStateMap = getVersionedAtomStateMap(version);
474 versionedAtomStateMap.forEach((atomState, atom) => {
475 const committedAtomState = committedAtomStateMap.get(atom);
476 if (atomState !== committedAtomState) {
477 const mounted = mountedMap.get(atom);
478 mounted == null ? void 0 : mounted.l.forEach((listener) => listener(version));
479 }
480 });
481 return;
482 }
483 while (pendingMap.size) {
484 const pending = Array.from(pendingMap);
485 pendingMap.clear();
486 pending.forEach(([atom, prevAtomState]) => {
487 const atomState = getAtomState(void 0, atom);
488 if (atomState && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
489 mountDependencies(void 0, atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
490 }
491 if (prevAtomState && "i" in prevAtomState && atomState && !("i" in atomState)) {
492 return;
493 }
494 const mounted = mountedMap.get(atom);
495 mounted == null ? void 0 : mounted.l.forEach((listener) => listener());
496 });
497 }
498 if ((import.meta.env && import.meta.env.MODE) !== "production") {
499 stateListeners.forEach((l) => l());
500 }
501 };
502 const commitVersionedAtomStateMap = (version) => {
503 const versionedAtomStateMap = getVersionedAtomStateMap(version);
504 versionedAtomStateMap.forEach((atomState, atom) => {
505 const prevAtomState = committedAtomStateMap.get(atom);
506 if (!prevAtomState || atomState.r > prevAtomState.r || "v" in atomState && atomState.r === prevAtomState.r && atomState.d !== prevAtomState.d) {
507 committedAtomStateMap.set(atom, atomState);
508 if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
509 mountDependencies(version, atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
510 }
511 }
512 });
513 };
514 const commitAtom = (_atom, version) => {
515 if (version) {
516 commitVersionedAtomStateMap(version);
517 }
518 flushPending(void 0);
519 };
520 const subscribeAtom = (atom, callback, version) => {
521 const mounted = addAtom(version, atom);
522 const listeners = mounted.l;
523 listeners.add(callback);
524 return () => {
525 listeners.delete(callback);
526 delAtom(version, atom);
527 };
528 };
529 const restoreAtoms = (values, version) => {
530 for (const [atom, value] of values) {
531 if (hasInitialValue(atom)) {
532 setAtomPromiseOrValue(version, atom, value);
533 invalidateDependents(version, atom);
534 }
535 }
536 flushPending(version);
537 };
538 if ((import.meta.env && import.meta.env.MODE) !== "production") {
539 return {
540 [READ_ATOM]: readAtom,
541 [WRITE_ATOM]: writeAtom,
542 [COMMIT_ATOM]: commitAtom,
543 [SUBSCRIBE_ATOM]: subscribeAtom,
544 [RESTORE_ATOMS]: restoreAtoms,
545 [DEV_SUBSCRIBE_STATE]: (l) => {
546 stateListeners.add(l);
547 return () => {
548 stateListeners.delete(l);
549 };
550 },
551 [DEV_GET_MOUNTED_ATOMS]: () => mountedAtoms.values(),
552 [DEV_GET_ATOM_STATE]: (a) => committedAtomStateMap.get(a),
553 [DEV_GET_MOUNTED]: (a) => mountedMap.get(a)
554 };
555 }
556 return {
557 [READ_ATOM]: readAtom,
558 [WRITE_ATOM]: writeAtom,
559 [COMMIT_ATOM]: commitAtom,
560 [SUBSCRIBE_ATOM]: subscribeAtom,
561 [RESTORE_ATOMS]: restoreAtoms
562 };
563};
564const createStoreForExport = (initialValues) => {
565 const store = createStore(initialValues);
566 const get = (atom) => {
567 const atomState = store[READ_ATOM](atom);
568 if ("e" in atomState) {
569 throw atomState.e;
570 }
571 if ("p" in atomState) {
572 return void 0;
573 }
574 return atomState.v;
575 };
576 const asyncGet = (atom) => new Promise((resolve, reject) => {
577 const atomState = store[READ_ATOM](atom);
578 if ("e" in atomState) {
579 reject(atomState.e);
580 } else if ("p" in atomState) {
581 resolve(atomState.p.then(() => asyncGet(atom)));
582 } else {
583 resolve(atomState.v);
584 }
585 });
586 const set = (atom, update) => store[WRITE_ATOM](atom, update);
587 const sub = (atom, callback) => store[SUBSCRIBE_ATOM](atom, callback);
588 return {
589 get,
590 asyncGet,
591 set,
592 sub,
593 SECRET_INTERNAL_store: store
594 };
595};
596
597const createScopeContainer = (initialValues, unstable_createStore) => {
598 const store = unstable_createStore ? unstable_createStore(initialValues).SECRET_INTERNAL_store : createStore(initialValues);
599 return { s: store };
600};
601const ScopeContextMap = /* @__PURE__ */ new Map();
602const getScopeContext = (scope) => {
603 if (!ScopeContextMap.has(scope)) {
604 ScopeContextMap.set(scope, createContext(createScopeContainer()));
605 }
606 return ScopeContextMap.get(scope);
607};
608
609const Provider = ({
610 children,
611 initialValues,
612 scope,
613 unstable_createStore,
614 unstable_enableVersionedWrite
615}) => {
616 const [version, setVersion] = useState({});
617 useEffect(() => {
618 const scopeContainer = scopeContainerRef.current;
619 if (scopeContainer.w) {
620 scopeContainer.s[COMMIT_ATOM](null, version);
621 delete version.p;
622 scopeContainer.v = version;
623 }
624 }, [version]);
625 const scopeContainerRef = useRef();
626 if (!scopeContainerRef.current) {
627 const scopeContainer = createScopeContainer(initialValues, unstable_createStore);
628 if (unstable_enableVersionedWrite) {
629 let retrying = 0;
630 scopeContainer.w = (write) => {
631 setVersion((parentVersion) => {
632 const nextVersion = retrying ? parentVersion : { p: parentVersion };
633 write(nextVersion);
634 return nextVersion;
635 });
636 };
637 scopeContainer.v = version;
638 scopeContainer.r = (fn) => {
639 ++retrying;
640 fn();
641 --retrying;
642 };
643 }
644 scopeContainerRef.current = scopeContainer;
645 }
646 const ScopeContainerContext = getScopeContext(scope);
647 return createElement(ScopeContainerContext.Provider, {
648 value: scopeContainerRef.current
649 }, children);
650};
651
652let keyCount = 0;
653function atom(read, write) {
654 const key = `atom${++keyCount}`;
655 const config = {
656 toString: () => key
657 };
658 if (typeof read === "function") {
659 config.read = read;
660 } else {
661 config.init = read;
662 config.read = (get) => get(config);
663 config.write = (get, set, update) => set(config, typeof update === "function" ? update(get(config)) : update);
664 }
665 if (write) {
666 config.write = write;
667 }
668 return config;
669}
670
671function useAtomValue(atom, scope) {
672 const ScopeContext = getScopeContext(scope);
673 const scopeContainer = useContext(ScopeContext);
674 const { s: store, v: versionFromProvider } = scopeContainer;
675 const getAtomValue = (version2) => {
676 const atomState = store[READ_ATOM](atom, version2);
677 if ("e" in atomState) {
678 throw atomState.e;
679 }
680 if ("p" in atomState) {
681 throw atomState.p;
682 }
683 if ("v" in atomState) {
684 return atomState.v;
685 }
686 throw new Error("no atom value");
687 };
688 const [[version, valueFromReducer, atomFromReducer], rerenderIfChanged] = useReducer((prev, nextVersion) => {
689 const nextValue = getAtomValue(nextVersion);
690 if (Object.is(prev[1], nextValue) && prev[2] === atom) {
691 return prev;
692 }
693 return [nextVersion, nextValue, atom];
694 }, versionFromProvider, (initialVersion) => {
695 const initialValue = getAtomValue(initialVersion);
696 return [initialVersion, initialValue, atom];
697 });
698 let value = valueFromReducer;
699 if (atomFromReducer !== atom) {
700 rerenderIfChanged(version);
701 value = getAtomValue(version);
702 }
703 useEffect(() => {
704 const { v: versionFromProvider2 } = scopeContainer;
705 if (versionFromProvider2) {
706 store[COMMIT_ATOM](atom, versionFromProvider2);
707 }
708 const unsubscribe = store[SUBSCRIBE_ATOM](atom, rerenderIfChanged, versionFromProvider2);
709 rerenderIfChanged(versionFromProvider2);
710 return unsubscribe;
711 }, [store, atom, scopeContainer]);
712 useEffect(() => {
713 store[COMMIT_ATOM](atom, version);
714 });
715 useDebugValue(value);
716 return value;
717}
718
719function useSetAtom(atom, scope) {
720 const ScopeContext = getScopeContext(scope);
721 const { s: store, w: versionedWrite } = useContext(ScopeContext);
722 const setAtom = useCallback((update) => {
723 if ((import.meta.env && import.meta.env.MODE) !== "production" && !("write" in atom)) {
724 throw new Error("not writable atom");
725 }
726 const write = (version) => store[WRITE_ATOM](atom, update, version);
727 return versionedWrite ? versionedWrite(write) : write();
728 }, [store, versionedWrite, atom]);
729 return setAtom;
730}
731
732function useAtom(atom, scope) {
733 if ("scope" in atom) {
734 console.warn("atom.scope is deprecated. Please do useAtom(atom, scope) instead.");
735 scope = atom.scope;
736 }
737 return [
738 useAtomValue(atom, scope),
739 useSetAtom(atom, scope)
740 ];
741}
742
743export { Provider, getScopeContext as SECRET_INTERNAL_getScopeContext, atom, createStoreForExport as unstable_createStore, useAtom, useAtomValue, useSetAtom };