UNPKG

27.3 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 const s = getAtomState(version, a);
389 if (s && "p" in s && s.p === aState.p) {
390 return new Promise((resolve) => setTimeout(resolve)).then(
391 () => writeGetter(a, options)
392 );
393 }
394 return writeGetter(a, options);
395 });
396 }
397 if ((import.meta.env && import.meta.env.MODE) !== "production") {
398 console.info(
399 "Reading pending atom state in write operation. We throw a promise for now.",
400 a
401 );
402 }
403 throw aState.p;
404 }
405 if ("v" in aState) {
406 return aState.v;
407 }
408 if ((import.meta.env && import.meta.env.MODE) !== "production") {
409 console.warn(
410 "[Bug] no value found while reading atom in write operation. This is probably a bug.",
411 a
412 );
413 }
414 throw new Error("no value found");
415 };
416 const setter = (a, v) => {
417 let promiseOrVoid2;
418 if (a === atom) {
419 if (!hasInitialValue(a)) {
420 throw new Error("atom not writable");
421 }
422 const versionSet = cancelAllSuspensePromiseInCache(a);
423 versionSet.forEach((cancelledVersion) => {
424 if (cancelledVersion !== version) {
425 setAtomPromiseOrValue(cancelledVersion, a, v);
426 }
427 });
428 const prevAtomState = getAtomState(version, a);
429 const nextAtomState = setAtomPromiseOrValue(version, a, v);
430 if (prevAtomState !== nextAtomState) {
431 invalidateDependents(version, a);
432 }
433 } else {
434 promiseOrVoid2 = writeAtomState(version, a, v);
435 }
436 if (!isSync) {
437 flushPending(version);
438 }
439 return promiseOrVoid2;
440 };
441 const promiseOrVoid = atom.write(writeGetter, setter, update);
442 isSync = false;
443 return promiseOrVoid;
444 };
445 const writeAtom = (writingAtom, update, version) => {
446 const promiseOrVoid = writeAtomState(version, writingAtom, update);
447 flushPending(version);
448 return promiseOrVoid;
449 };
450 const isActuallyWritableAtom = (atom) => !!atom.write;
451 const mountAtom = (version, atom, initialDependent) => {
452 const mounted = {
453 t: new Set(initialDependent && [initialDependent]),
454 l: /* @__PURE__ */ new Set()
455 };
456 mountedMap.set(atom, mounted);
457 if ((import.meta.env && import.meta.env.MODE) !== "production") {
458 mountedAtoms.add(atom);
459 }
460 const atomState = readAtomState(void 0, atom);
461 atomState.d.forEach((_, a) => {
462 const aMounted = mountedMap.get(a);
463 if (aMounted) {
464 aMounted.t.add(atom);
465 } else {
466 if (a !== atom) {
467 mountAtom(version, a, atom);
468 }
469 }
470 });
471 if (isActuallyWritableAtom(atom) && atom.onMount) {
472 const setAtom = (update) => writeAtom(atom, update, version);
473 const onUnmount = atom.onMount(setAtom);
474 version = void 0;
475 if (onUnmount) {
476 mounted.u = onUnmount;
477 }
478 }
479 return mounted;
480 };
481 const unmountAtom = (version, atom) => {
482 var _a;
483 const onUnmount = (_a = mountedMap.get(atom)) == null ? void 0 : _a.u;
484 if (onUnmount) {
485 onUnmount();
486 }
487 mountedMap.delete(atom);
488 if ((import.meta.env && import.meta.env.MODE) !== "production") {
489 mountedAtoms.delete(atom);
490 }
491 const atomState = getAtomState(version, atom);
492 if (atomState) {
493 if ("p" in atomState) {
494 cancelSuspensePromise(atomState.p);
495 }
496 atomState.d.forEach((_, a) => {
497 if (a !== atom) {
498 const mounted = mountedMap.get(a);
499 if (mounted) {
500 mounted.t.delete(atom);
501 if (canUnmountAtom(a, mounted)) {
502 unmountAtom(version, a);
503 }
504 }
505 }
506 });
507 } else if ((import.meta.env && import.meta.env.MODE) !== "production") {
508 console.warn("[Bug] could not find atom state to unmount", atom);
509 }
510 };
511 const mountDependencies = (version, atom, atomState, prevReadDependencies) => {
512 const dependencies = new Set(atomState.d.keys());
513 prevReadDependencies == null ? void 0 : prevReadDependencies.forEach((_, a) => {
514 if (dependencies.has(a)) {
515 dependencies.delete(a);
516 return;
517 }
518 const mounted = mountedMap.get(a);
519 if (mounted) {
520 mounted.t.delete(atom);
521 if (canUnmountAtom(a, mounted)) {
522 unmountAtom(version, a);
523 }
524 }
525 });
526 dependencies.forEach((a) => {
527 const mounted = mountedMap.get(a);
528 if (mounted) {
529 mounted.t.add(atom);
530 } else if (mountedMap.has(atom)) {
531 mountAtom(version, a, atom);
532 }
533 });
534 };
535 const flushPending = (version) => {
536 if (version) {
537 const versionedAtomStateMap = getVersionedAtomStateMap(version);
538 versionedAtomStateMap.forEach((atomState, atom) => {
539 const committedAtomState = committedAtomStateMap.get(atom);
540 if (atomState !== committedAtomState) {
541 const mounted = mountedMap.get(atom);
542 mounted == null ? void 0 : mounted.l.forEach((listener) => listener(version));
543 }
544 });
545 return;
546 }
547 while (pendingMap.size) {
548 const pending = Array.from(pendingMap);
549 pendingMap.clear();
550 pending.forEach(([atom, prevAtomState]) => {
551 const atomState = getAtomState(void 0, atom);
552 if (atomState && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
553 mountDependencies(void 0, atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
554 }
555 if (prevAtomState && !prevAtomState.y && (atomState == null ? void 0 : atomState.y)) {
556 return;
557 }
558 const mounted = mountedMap.get(atom);
559 mounted == null ? void 0 : mounted.l.forEach((listener) => listener());
560 });
561 }
562 if ((import.meta.env && import.meta.env.MODE) !== "production") {
563 stateListeners.forEach((l) => l());
564 }
565 };
566 const commitVersionedAtomStateMap = (version) => {
567 const versionedAtomStateMap = getVersionedAtomStateMap(version);
568 versionedAtomStateMap.forEach((atomState, atom) => {
569 const prevAtomState = committedAtomStateMap.get(atom);
570 if (!prevAtomState || atomState.r > prevAtomState.r || atomState.y !== prevAtomState.y || atomState.r === prevAtomState.r && atomState.d !== prevAtomState.d) {
571 committedAtomStateMap.set(atom, atomState);
572 if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
573 mountDependencies(version, atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
574 }
575 }
576 });
577 };
578 const commitAtom = (_atom, version) => {
579 if (version) {
580 commitVersionedAtomStateMap(version);
581 }
582 flushPending(void 0);
583 };
584 const subscribeAtom = (atom, callback, version) => {
585 const mounted = addAtom(version, atom);
586 const listeners = mounted.l;
587 listeners.add(callback);
588 return () => {
589 listeners.delete(callback);
590 delAtom(version, atom);
591 };
592 };
593 const restoreAtoms = (values, version) => {
594 for (const [atom, value] of values) {
595 if (hasInitialValue(atom)) {
596 setAtomPromiseOrValue(version, atom, value);
597 invalidateDependents(version, atom);
598 }
599 }
600 flushPending(version);
601 };
602 if ((import.meta.env && import.meta.env.MODE) !== "production") {
603 return {
604 [READ_ATOM]: readAtom,
605 [WRITE_ATOM]: writeAtom,
606 [COMMIT_ATOM]: commitAtom,
607 [SUBSCRIBE_ATOM]: subscribeAtom,
608 [RESTORE_ATOMS]: restoreAtoms,
609 [DEV_SUBSCRIBE_STATE]: (l) => {
610 stateListeners.add(l);
611 return () => {
612 stateListeners.delete(l);
613 };
614 },
615 [DEV_GET_MOUNTED_ATOMS]: () => mountedAtoms.values(),
616 [DEV_GET_ATOM_STATE]: (a) => committedAtomStateMap.get(a),
617 [DEV_GET_MOUNTED]: (a) => mountedMap.get(a)
618 };
619 }
620 return {
621 [READ_ATOM]: readAtom,
622 [WRITE_ATOM]: writeAtom,
623 [COMMIT_ATOM]: commitAtom,
624 [SUBSCRIBE_ATOM]: subscribeAtom,
625 [RESTORE_ATOMS]: restoreAtoms
626 };
627};
628const createStoreForExport = (initialValues) => {
629 const store = createStore(initialValues);
630 const get = (atom) => {
631 const atomState = store[READ_ATOM](atom);
632 if ("e" in atomState) {
633 throw atomState.e;
634 }
635 if ("p" in atomState) {
636 return void 0;
637 }
638 return atomState.v;
639 };
640 const asyncGet = (atom) => new Promise((resolve, reject) => {
641 const atomState = store[READ_ATOM](atom);
642 if ("e" in atomState) {
643 reject(atomState.e);
644 } else if ("p" in atomState) {
645 resolve(atomState.p.then(() => asyncGet(atom)));
646 } else {
647 resolve(atomState.v);
648 }
649 });
650 const set = (atom, update) => store[WRITE_ATOM](atom, update);
651 const sub = (atom, callback) => store[SUBSCRIBE_ATOM](atom, callback);
652 return {
653 get,
654 asyncGet,
655 set,
656 sub,
657 SECRET_INTERNAL_store: store
658 };
659};
660
661const createScopeContainer = (initialValues, unstable_createStore) => {
662 const store = unstable_createStore ? unstable_createStore(initialValues).SECRET_INTERNAL_store : createStore(initialValues);
663 return { s: store };
664};
665const ScopeContextMap = /* @__PURE__ */ new Map();
666const getScopeContext = (scope) => {
667 if (!ScopeContextMap.has(scope)) {
668 ScopeContextMap.set(scope, createContext(createScopeContainer()));
669 }
670 return ScopeContextMap.get(scope);
671};
672
673const Provider = ({
674 children,
675 initialValues,
676 scope,
677 unstable_createStore,
678 unstable_enableVersionedWrite
679}) => {
680 const [version, setVersion] = useState({});
681 useEffect(() => {
682 const scopeContainer = scopeContainerRef.current;
683 if (scopeContainer.w) {
684 scopeContainer.s[COMMIT_ATOM](null, version);
685 delete version.p;
686 scopeContainer.v = version;
687 }
688 }, [version]);
689 const scopeContainerRef = useRef();
690 if (!scopeContainerRef.current) {
691 const scopeContainer = createScopeContainer(
692 initialValues,
693 unstable_createStore
694 );
695 if (unstable_enableVersionedWrite) {
696 let retrying = 0;
697 scopeContainer.w = (write) => {
698 setVersion((parentVersion) => {
699 const nextVersion = retrying ? parentVersion : { p: parentVersion };
700 write(nextVersion);
701 return nextVersion;
702 });
703 };
704 scopeContainer.v = version;
705 scopeContainer.r = (fn) => {
706 ++retrying;
707 fn();
708 --retrying;
709 };
710 }
711 scopeContainerRef.current = scopeContainer;
712 }
713 const ScopeContainerContext = getScopeContext(scope);
714 return createElement(
715 ScopeContainerContext.Provider,
716 {
717 value: scopeContainerRef.current
718 },
719 children
720 );
721};
722
723let keyCount = 0;
724function atom(read, write) {
725 const key = `atom${++keyCount}`;
726 const config = {
727 toString: () => key
728 };
729 if (typeof read === "function") {
730 config.read = read;
731 } else {
732 config.init = read;
733 config.read = (get) => get(config);
734 config.write = (get, set, update) => set(config, typeof update === "function" ? update(get(config)) : update);
735 }
736 if (write) {
737 config.write = write;
738 }
739 return config;
740}
741
742function useAtomValue(atom, scope) {
743 const ScopeContext = getScopeContext(scope);
744 const scopeContainer = useContext(ScopeContext);
745 const { s: store, v: versionFromProvider } = scopeContainer;
746 const getAtomValue = (version2) => {
747 const atomState = store[READ_ATOM](atom, version2);
748 if ((import.meta.env && import.meta.env.MODE) !== "production" && !atomState.y) {
749 throw new Error("should not be invalidated");
750 }
751 if ("e" in atomState) {
752 throw atomState.e;
753 }
754 if ("p" in atomState) {
755 throw atomState.p;
756 }
757 if ("v" in atomState) {
758 return atomState.v;
759 }
760 throw new Error("no atom value");
761 };
762 const [[version, valueFromReducer, atomFromReducer], rerenderIfChanged] = useReducer(
763 (prev, nextVersion) => {
764 const nextValue = getAtomValue(nextVersion);
765 if (Object.is(prev[1], nextValue) && prev[2] === atom) {
766 return prev;
767 }
768 return [nextVersion, nextValue, atom];
769 },
770 versionFromProvider,
771 (initialVersion) => {
772 const initialValue = getAtomValue(initialVersion);
773 return [initialVersion, initialValue, atom];
774 }
775 );
776 let value = valueFromReducer;
777 if (atomFromReducer !== atom) {
778 rerenderIfChanged(version);
779 value = getAtomValue(version);
780 }
781 useEffect(() => {
782 const { v: versionFromProvider2 } = scopeContainer;
783 if (versionFromProvider2) {
784 store[COMMIT_ATOM](atom, versionFromProvider2);
785 }
786 const unsubscribe = store[SUBSCRIBE_ATOM](
787 atom,
788 rerenderIfChanged,
789 versionFromProvider2
790 );
791 rerenderIfChanged(versionFromProvider2);
792 return unsubscribe;
793 }, [store, atom, scopeContainer]);
794 useEffect(() => {
795 store[COMMIT_ATOM](atom, version);
796 });
797 useDebugValue(value);
798 return value;
799}
800
801function useSetAtom(atom, scope) {
802 const ScopeContext = getScopeContext(scope);
803 const { s: store, w: versionedWrite } = useContext(ScopeContext);
804 const setAtom = useCallback(
805 (update) => {
806 if ((import.meta.env && import.meta.env.MODE) !== "production" && !("write" in atom)) {
807 throw new Error("not writable atom");
808 }
809 const write = (version) => store[WRITE_ATOM](atom, update, version);
810 return versionedWrite ? versionedWrite(write) : write();
811 },
812 [store, versionedWrite, atom]
813 );
814 return setAtom;
815}
816
817function useAtom(atom, scope) {
818 if ("scope" in atom) {
819 console.warn(
820 "atom.scope is deprecated. Please do useAtom(atom, scope) instead."
821 );
822 scope = atom.scope;
823 }
824 return [
825 useAtomValue(atom, scope),
826 useSetAtom(atom, scope)
827 ];
828}
829
830export { Provider, getScopeContext as SECRET_INTERNAL_getScopeContext, registerPromiseAbort as SECRET_INTERNAL_registerPromiseAbort, atom, createStoreForExport as unstable_createStore, useAtom, useAtomValue, useSetAtom };