UNPKG

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