UNPKG

105 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var react = _interopDefault(require('react'));
8var reactDom = _interopDefault(require('react-dom'));
9
10/**
11 * Copyright (c) Facebook, Inc. and its affiliates.
12 *
13 * This source code is licensed under the MIT license found in the
14 * LICENSE file in the root directory of this source tree.
15 *
16 * @emails oncall+recoil
17 *
18 * @format
19 */
20
21function sprintf(format, ...args) {
22 let index = 0;
23 return format.replace(/%s/g, () => String(args[index++]));
24}
25
26var Recoil_sprintf = sprintf;
27
28// @oss-only
29// prettier-ignore
30
31
32function expectationViolation(format, ...args) {
33 // @oss-only
34 {
35 // @oss-only
36 const message = Recoil_sprintf.call(null, format, ...args); // @oss-only
37
38 const error = new Error(message); // @oss-only
39
40 error.name = 'Expectation Violation'; // @oss-only
41
42 console.error(error); // @oss-only
43 } // @oss-only
44
45} // @oss-only
46
47
48var Recoil_expectationViolation = expectationViolation;
49
50/**
51 * Copyright (c) Facebook, Inc. and its affiliates.
52 *
53 * This source code is licensed under the MIT license found in the
54 * LICENSE file in the root directory of this source tree.
55 *
56 * @emails oncall+recoil
57 *
58 * @format
59 */
60// prettier-ignore
61
62/* eslint-disable no-lone-blocks */
63// this {} block is necessary to keep prettier off on internal repo
64// @fb-only: {
65
66function recoverableViolation( // @oss-only
67message, // @oss-only
68projectName, // @oss-only
69{
70 error
71} = {}) {
72 // @oss-only
73 {
74 // @oss-only
75 console.error(message, error); // @oss-only
76 } // @oss-only
77
78
79 return null; // @oss-only
80} // @oss-only
81// @fb-only: }
82
83/* eslint-enable no-lone-blocks */
84
85
86var Recoil_recoverableViolation = recoverableViolation;
87
88function _defineProperty(obj, key, value) {
89 if (key in obj) {
90 Object.defineProperty(obj, key, {
91 value: value,
92 enumerable: true,
93 configurable: true,
94 writable: true
95 });
96 } else {
97 obj[key] = value;
98 }
99
100 return obj;
101}
102
103/**
104 * Copyright (c) Facebook, Inc. and its affiliates.
105 *
106 * This source code is licensed under the MIT license found in the
107 * LICENSE file in the root directory of this source tree.
108 *
109 * @emails oncall+recoil
110 *
111 * @format
112 */
113
114// eslint-disable-next-line no-unused-vars
115class AbstractRecoilValue {
116 constructor(newKey) {
117 _defineProperty(this, "key", void 0);
118
119 this.key = newKey;
120 }
121
122}
123
124class RecoilState extends AbstractRecoilValue {}
125
126class RecoilValueReadOnly extends AbstractRecoilValue {}
127
128function isRecoilValue(x) {
129 return x instanceof RecoilState || x instanceof RecoilValueReadOnly;
130}
131
132var Recoil_RecoilValue = {
133 AbstractRecoilValue,
134 RecoilState,
135 RecoilValueReadOnly,
136 isRecoilValue
137};
138
139var Recoil_RecoilValue_1 = Recoil_RecoilValue.AbstractRecoilValue;
140var Recoil_RecoilValue_2 = Recoil_RecoilValue.RecoilState;
141var Recoil_RecoilValue_3 = Recoil_RecoilValue.RecoilValueReadOnly;
142var Recoil_RecoilValue_4 = Recoil_RecoilValue.isRecoilValue;
143
144var Recoil_RecoilValue$1 = /*#__PURE__*/Object.freeze({
145 __proto__: null,
146 AbstractRecoilValue: Recoil_RecoilValue_1,
147 RecoilState: Recoil_RecoilValue_2,
148 RecoilValueReadOnly: Recoil_RecoilValue_3,
149 isRecoilValue: Recoil_RecoilValue_4
150});
151
152class DefaultValue {}
153
154const DEFAULT_VALUE = new DefaultValue();
155
156class RecoilValueNotReady extends Error {
157 constructor(key) {
158 super(`Tried to set the value of Recoil selector ${key} using an updater function, but it is an async selector in a pending or error state; this is not supported.`);
159 }
160
161}
162
163// flowlint-next-line unclear-type:off
164const nodes = new Map();
165/* eslint-disable no-redeclare */
166
167function registerNode(node) {
168 if (nodes.has(node.key)) {
169 const message = `Duplicate atom key "${node.key}". This is a FATAL ERROR in
170 production. But it is safe to ignore this warning if it occurred because of
171 hot module replacement.`; // TODO Need to figure out if there is a standard/open-source equivalent to see if hot module replacement is happening:
172 // prettier-ignore
173 // @fb-only: if (__DEV__) {
174 // @fb-only: const isAcceptingUpdate = require('__debug').isAcceptingUpdate;
175 // prettier-ignore
176 // @fb-only: if (typeof isAcceptingUpdate !== 'function' || !isAcceptingUpdate()) {
177 // @fb-only: expectationViolation(message, 'recoil');
178 // @fb-only: }
179 // prettier-ignore
180 // @fb-only: } else {
181
182 Recoil_recoverableViolation(message); // @fb-only: }
183 }
184
185 nodes.set(node.key, node);
186 return node.set == null ? new Recoil_RecoilValue$1.RecoilValueReadOnly(node.key) : new Recoil_RecoilValue$1.RecoilState(node.key);
187}
188/* eslint-enable no-redeclare */
189
190
191class NodeMissingError extends Error {} // flowlint-next-line unclear-type:off
192
193
194function getNode(key) {
195 const node = nodes.get(key);
196
197 if (node == null) {
198 throw new NodeMissingError(`Missing definition for RecoilValue: "${key}""`);
199 }
200
201 return node;
202}
203
204var Recoil_Node = {
205 nodes,
206 registerNode,
207 getNode,
208 NodeMissingError,
209 DefaultValue,
210 DEFAULT_VALUE,
211 RecoilValueNotReady
212};
213
214/**
215 * Copyright (c) Facebook, Inc. and its affiliates.
216 *
217 * This source code is licensed under the MIT license found in the
218 * LICENSE file in the root directory of this source tree.
219 *
220 * @emails oncall+recoil
221 *
222 * @format
223 */
224
225function enqueueExecution(s, f) {
226 f();
227}
228
229var Recoil_Queue = {
230 enqueueExecution
231};
232
233/**
234 * Copyright (c) Facebook, Inc. and its affiliates.
235 *
236 * This source code is licensed under the MIT license found in the
237 * LICENSE file in the root directory of this source tree.
238 *
239 * Utilities for working with built-in Maps and Sets without mutating them.
240 *
241 * @emails oncall+recoil
242 *
243 * @format
244 */
245
246function setByAddingToSet(set, v) {
247 const next = new Set(set);
248 next.add(v);
249 return next;
250}
251
252function setByDeletingFromSet(set, v) {
253 const next = new Set(set);
254 next.delete(v);
255 return next;
256}
257
258function mapBySettingInMap(map, k, v) {
259 const next = new Map(map);
260 next.set(k, v);
261 return next;
262}
263
264function mapByUpdatingInMap(map, k, updater) {
265 const next = new Map(map);
266 next.set(k, updater(next.get(k)));
267 return next;
268}
269
270function mapByDeletingFromMap(map, k) {
271 const next = new Map(map);
272 next.delete(k);
273 return next;
274}
275
276var Recoil_CopyOnWrite = {
277 setByAddingToSet,
278 setByDeletingFromSet,
279 mapBySettingInMap,
280 mapByUpdatingInMap,
281 mapByDeletingFromMap
282};
283
284/**
285 * Copyright (c) Facebook, Inc. and its affiliates.
286 *
287 * This source code is licensed under the MIT license found in the
288 * LICENSE file in the root directory of this source tree.
289 *
290 * Interface for `scheduler/tracing` to aid in profiling Recoil and Recoil apps.
291 *
292 * @emails oncall+recoil
293 *
294 * @format
295 */
296
297// flowlint-next-line untyped-import:off
298// @fb-only: const SchedulerTracing = require('SchedulerTracing');
299function trace(message, node, fn) {
300 // prettier-ignore
301 // @fb-only: if (__DEV__) {
302 // prettier-ignore
303 // @fb-only: if (
304 // prettier-ignore
305 // @fb-only: SchedulerTracing.unstable_trace !== undefined &&
306 // prettier-ignore
307 // @fb-only: window.performance !== undefined
308 // prettier-ignore
309 // @fb-only: ) {
310 // prettier-ignore
311 // @fb-only: return SchedulerTracing.unstable_trace(
312 // prettier-ignore
313 // @fb-only: `Recoil: ${message} for node: ${
314 // prettier-ignore
315 // @fb-only: typeof node === 'string' ? node : node.key
316 // prettier-ignore
317 // @fb-only: }`,
318 // prettier-ignore
319 // @fb-only: window.performance.now(),
320 // prettier-ignore
321 // @fb-only: fn,
322 // prettier-ignore
323 // @fb-only: );
324 // prettier-ignore
325 // @fb-only: }
326 // prettier-ignore
327 // @fb-only: }
328 return fn();
329}
330
331function wrap(fn) {
332 // prettier-ignore
333 // @fb-only: if (__DEV__) {
334 // prettier-ignore
335 // @fb-only: if (SchedulerTracing.unstable_wrap !== undefined) {
336 // prettier-ignore
337 // @fb-only: return SchedulerTracing.unstable_wrap(fn);
338 // prettier-ignore
339 // @fb-only: }
340 // prettier-ignore
341 // @fb-only: }
342 return fn;
343}
344
345var Recoil_Tracing = {
346 trace,
347 wrap
348};
349
350const {
351 mapByDeletingFromMap: mapByDeletingFromMap$1,
352 mapBySettingInMap: mapBySettingInMap$1,
353 mapByUpdatingInMap: mapByUpdatingInMap$1,
354 setByAddingToSet: setByAddingToSet$1
355} = Recoil_CopyOnWrite;
356
357
358
359const {
360 getNode: getNode$1
361} = Recoil_Node; // flowlint-next-line unclear-type:off
362
363
364const emptyMap = Object.freeze(new Map()); // flowlint-next-line unclear-type:off
365
366const emptySet = Object.freeze(new Set());
367
368class ReadOnlyRecoilValueError extends Error {} // Get the current value loadable of a node and update the state.
369// Update dependencies and subscriptions for selectors.
370// Update saved value validation for atoms.
371
372
373function getNodeLoadable(store, state, key) {
374 return getNode$1(key).get(store, state);
375} // Peek at the current value loadable for a node.
376// NOTE: This will ignore updating the state for subscriptions so use sparingly!!
377
378
379function peekNodeLoadable(store, state, key) {
380 return getNodeLoadable(store, state, key)[1];
381} // Write value directly to state bypassing the Node interface as the node
382// definitions may not have been loaded yet when processing the initial snapshot.
383
384
385function setUnvalidatedAtomValue(state, key, newValue) {
386 return { ...state,
387 atomValues: mapByDeletingFromMap$1(state.atomValues, key),
388 nonvalidatedAtoms: mapBySettingInMap$1(state.nonvalidatedAtoms, key, newValue),
389 dirtyAtoms: setByAddingToSet$1(state.dirtyAtoms, key)
390 };
391} // Set a node value and return the set of nodes that were actually written.
392// That does not include any downstream nodes which are dependent on them.
393
394
395function setNodeValue(store, state, key, newValue) {
396 const node = getNode$1(key);
397
398 if (node.set == null) {
399 throw new ReadOnlyRecoilValueError(`Attempt to set read-only RecoilValue: ${key}`);
400 }
401
402 const [newState, writtenNodes] = node.set(store, state, newValue);
403 return [newState, writtenNodes];
404} // Find all of the recursively dependent nodes
405
406
407function getDownstreamNodes(state, keys) {
408 const dependentNodes = new Set();
409 const visitedNodes = new Set();
410 const visitingNodes = Array.from(keys);
411
412 for (let key = visitingNodes.pop(); key; key = visitingNodes.pop()) {
413 var _state$nodeToNodeSubs;
414
415 dependentNodes.add(key);
416 visitedNodes.add(key);
417 const subscribedNodes = (_state$nodeToNodeSubs = state.nodeToNodeSubscriptions.get(key)) !== null && _state$nodeToNodeSubs !== void 0 ? _state$nodeToNodeSubs : emptySet;
418
419 for (const downstreamNode of subscribedNodes) {
420 if (!visitedNodes.has(downstreamNode)) {
421 visitingNodes.push(downstreamNode);
422 }
423 }
424 }
425
426 return dependentNodes;
427}
428
429let subscriptionID = 0;
430
431function subscribeComponentToNode(state, key, callback) {
432 const subID = subscriptionID++;
433 const newState = { ...state,
434 nodeToComponentSubscriptions: mapByUpdatingInMap$1(state.nodeToComponentSubscriptions, key, subsForAtom => mapBySettingInMap$1(subsForAtom !== null && subsForAtom !== void 0 ? subsForAtom : emptyMap, subID, ['TODO debug name', callback]))
435 };
436
437 function release(state) {
438 const newState = { ...state,
439 nodeToComponentSubscriptions: mapByUpdatingInMap$1(state.nodeToComponentSubscriptions, key, subsForAtom => mapByDeletingFromMap$1(subsForAtom !== null && subsForAtom !== void 0 ? subsForAtom : emptyMap, subID))
440 };
441 return newState;
442 }
443
444 return [newState, release];
445} // Fire or enqueue callbacks to rerender components that are subscribed to
446// nodes affected by the updatedNodes
447
448
449function fireNodeSubscriptions(store, updatedNodes, when) {
450 var _store$getState$nextT;
451
452 /*
453 This is called in two conditions: When an atom is set (with 'enqueue') and
454 when an async selector resolves (with 'now'). When an atom is set, we want
455 to use the latest dependencies that may have become dependencies due to
456 earlier changes in a batch. But if an async selector happens to resolve during
457 a batch, it should use the currently rendered output, and then the end of the
458 batch will trigger any further subscriptions due to new deps in the new state.
459 */
460 const state = when === 'enqueue' ? (_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree : store.getState().currentTree;
461 const dependentNodes = getDownstreamNodes(state, updatedNodes);
462
463 for (const key of dependentNodes) {
464 var _state$nodeToComponen;
465
466 ((_state$nodeToComponen = state.nodeToComponentSubscriptions.get(key)) !== null && _state$nodeToComponen !== void 0 ? _state$nodeToComponen : []).forEach(([_debugName, cb]) => {
467 when === 'enqueue' ? store.getState().queuedComponentCallbacks.push(cb) : cb(state);
468 });
469 } // Wake all suspended components so the right one(s) can try to re-render.
470 // We need to wake up components not just when some asynchronous selector
471 // resolved (when === 'now'), but also when changing synchronous values because
472 // they may cause a selector to change from asynchronous to synchronous, in
473 // which case there would be no follow-up asynchronous resolution to wake us up.
474 // TODO OPTIMIZATION Only wake up related downstream components
475
476
477 Recoil_Tracing.trace('value became available, waking components', Array.from(updatedNodes).join(', '), () => {
478 const resolvers = store.getState().suspendedComponentResolvers;
479 resolvers.forEach(r => r());
480 resolvers.clear();
481 });
482}
483
484function detectCircularDependencies(state, stack) {
485 if (!stack.length) {
486 return;
487 }
488
489 const leaf = stack[stack.length - 1];
490 const downstream = state.nodeToNodeSubscriptions.get(leaf);
491
492 if (!(downstream === null || downstream === void 0 ? void 0 : downstream.size)) {
493 return;
494 }
495
496 const root = stack[0];
497
498 if (downstream.has(root)) {
499 throw new Error(`Recoil selector has circular dependencies: ${[...stack, root].reverse().join(' \u2192 ')}`);
500 }
501
502 for (const next of downstream) {
503 detectCircularDependencies(state, [...stack, next]);
504 }
505}
506
507var Recoil_FunctionalCore = {
508 getNodeLoadable,
509 peekNodeLoadable,
510 setNodeValue,
511 setUnvalidatedAtomValue,
512 subscribeComponentToNode,
513 fireNodeSubscriptions,
514 detectCircularDependencies
515};
516
517/**
518 * Copyright (c) Facebook, Inc. and its affiliates.
519 *
520 * This source code is licensed under the MIT license found in the
521 * LICENSE file in the root directory of this source tree.
522 *
523 * @emails oncall+recoil
524 *
525 * @format
526 */
527/**
528 * Returns a new Map object with the same keys as the original, but with the
529 * values replaced with the output of the given callback function.
530 */
531
532function mapMap(map, callback) {
533 const result = new Map();
534 map.forEach((value, key) => {
535 result.set(key, callback(value, key));
536 });
537 return result;
538}
539
540var Recoil_mapMap = mapMap;
541
542const {
543 getNodeLoadable: getNodeLoadable$1,
544 peekNodeLoadable: peekNodeLoadable$1,
545 setNodeValue: setNodeValue$1,
546 setUnvalidatedAtomValue: setUnvalidatedAtomValue$1,
547 subscribeComponentToNode: subscribeComponentToNode$1
548} = Recoil_FunctionalCore;
549
550const {
551 RecoilValueNotReady: RecoilValueNotReady$1
552} = Recoil_Node;
553
554const {
555 AbstractRecoilValue: AbstractRecoilValue$1,
556 RecoilState: RecoilState$1,
557 RecoilValueReadOnly: RecoilValueReadOnly$1
558} = Recoil_RecoilValue$1;
559
560function getRecoilValueAsLoadable(store, {
561 key
562}) {
563 let result; // Save any state changes during read, such as validating atoms,
564 // updated selector subscriptions/dependencies, &c.
565
566 Recoil_Tracing.trace('get RecoilValue', key, () => store.replaceState(Recoil_Tracing.wrap(state => {
567 const [newState, loadable] = getNodeLoadable$1(store, state, key);
568 result = loadable;
569 return newState;
570 })));
571 return result; // flowlint-line unclear-type:off
572}
573
574function setRecoilValue(store, {
575 key
576}, newValue) {
577 Recoil_Tracing.trace('set RecoilValue', key, () => store.replaceState(Recoil_Tracing.wrap(state => {
578 const [newState, writtenNodes] = setNodeValue$1(store, state, key, newValue);
579 store.fireNodeSubscriptions(writtenNodes, 'enqueue');
580 return newState;
581 })));
582}
583
584function setUnvalidatedRecoilValue(store, {
585 key
586}, newValue) {
587 Recoil_Tracing.trace('set unvalidated persisted atom', key, () => store.replaceState(Recoil_Tracing.wrap(state => {
588 const newState = setUnvalidatedAtomValue$1(state, key, newValue);
589 store.fireNodeSubscriptions(new Set([key]), 'enqueue');
590 return newState;
591 })));
592}
593
594function valueFromValueOrUpdater(store, {
595 key
596}, valueOrUpdater) {
597 if (typeof valueOrUpdater === 'function') {
598 var _storeState$nextTree;
599
600 // Updater form: pass in the current value. Throw if the current value
601 // is unavailable (namely when updating an async selector that's
602 // pending or errored):
603 const storeState = store.getState();
604 const state = (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree; // NOTE: This will not update state with node subscriptions.
605
606 const current = peekNodeLoadable$1(store, state, key);
607
608 if (current.state === 'loading') {
609 throw new RecoilValueNotReady$1(key);
610 } else if (current.state === 'hasError') {
611 throw current.contents;
612 } // T itself may be a function, so our refinement is not sufficient:
613
614
615 return valueOrUpdater(current.contents); // flowlint-line unclear-type:off
616 } else {
617 return valueOrUpdater;
618 }
619}
620
621function subscribeToRecoilValue(store, {
622 key
623}, callback) {
624 let newState, releaseFn;
625 Recoil_Tracing.trace('subscribe component to RecoilValue', key, () => store.replaceState(Recoil_Tracing.wrap(state => {
626 [newState, releaseFn] = subscribeComponentToNode$1(state, key, callback);
627 return newState;
628 })));
629 return {
630 release: store => store.replaceState(releaseFn)
631 };
632}
633
634var Recoil_RecoilValueInterface = {
635 RecoilValueReadOnly: RecoilValueReadOnly$1,
636 AbstractRecoilValue: AbstractRecoilValue$1,
637 RecoilState: RecoilState$1,
638 valueFromValueOrUpdater,
639 getRecoilValueAsLoadable,
640 setRecoilValue,
641 setUnvalidatedRecoilValue,
642 subscribeToRecoilValue
643};
644
645/**
646 * Copyright (c) Facebook, Inc. and its affiliates.
647 *
648 * This source code is licensed under the MIT license found in the
649 * LICENSE file in the root directory of this source tree.
650 *
651 * @emails oncall+recoil
652 *
653 * @format
654 */
655
656// TODO We could just store T instead of a Loadable<T> in atomValues
657// flowlint-next-line unclear-type:off
658// StoreState represents the state of a Recoil context. It is global and mutable.
659// It is updated only during effects, except that the nextTree property is updated
660// when atom values change and async requests resolve, and suspendedComponentResolvers
661// is updated when components are suspended.
662function makeEmptyTreeState() {
663 return {
664 transactionMetadata: {},
665 atomValues: new Map(),
666 nonvalidatedAtoms: new Map(),
667 dirtyAtoms: new Set(),
668 nodeDeps: new Map(),
669 nodeToNodeSubscriptions: new Map(),
670 nodeToComponentSubscriptions: new Map()
671 };
672}
673
674function makeStoreState(treeState) {
675 return {
676 currentTree: treeState,
677 nextTree: null,
678 transactionSubscriptions: new Map(),
679 queuedComponentCallbacks: [],
680 suspendedComponentResolvers: new Set()
681 };
682}
683
684function makeEmptyStoreState() {
685 return makeStoreState(makeEmptyTreeState());
686}
687
688var Recoil_State = {
689 makeEmptyTreeState,
690 makeEmptyStoreState,
691 makeStoreState
692};
693
694const {
695 DEFAULT_VALUE: DEFAULT_VALUE$1
696} = Recoil_Node;
697
698const {
699 getRecoilValueAsLoadable: getRecoilValueAsLoadable$1,
700 setRecoilValue: setRecoilValue$1,
701 valueFromValueOrUpdater: valueFromValueOrUpdater$1
702} = Recoil_RecoilValueInterface;
703
704const {
705 makeEmptyTreeState: makeEmptyTreeState$1,
706 makeStoreState: makeStoreState$1
707} = Recoil_State;
708
709function makeStore(treeState) {
710 const storeState = makeStoreState$1(treeState);
711 const store = {
712 getState: () => storeState,
713 replaceState: replacer => {
714 storeState.currentTree = replacer(storeState.currentTree); // no batching so nextTree is never active
715 },
716 subscribeToTransactions: () => {
717 throw new Error('Cannot subscribe to Snapshots');
718 },
719 addTransactionMetadata: () => {
720 throw new Error('Cannot subscribe to Snapshots');
721 },
722 fireNodeSubscriptions: () => {}
723 };
724 return store;
725} // A "Snapshot" is "read-only" and captures a specific set of values of atoms.
726// However, the data-flow-graph and selector values may evolve as selector
727// evaluation functions are executed and async selectors resolve.
728
729
730class Snapshot {
731 constructor(treeState) {
732 _defineProperty(this, "_store", void 0);
733
734 _defineProperty(this, "getLoadable", recoilValue => getRecoilValueAsLoadable$1(this._store, recoilValue));
735
736 _defineProperty(this, "getPromise", recoilValue => this.getLoadable(recoilValue).toPromise());
737
738 _defineProperty(this, "map", mapper => {
739 const mutableSnapshot = new MutableSnapshot(this._store.getState().currentTree);
740 mapper(mutableSnapshot);
741 const newState = mutableSnapshot.getStore_INTERNAL().getState().currentTree;
742 return cloneSnapshot(newState);
743 });
744
745 _defineProperty(this, "asyncMap", async mapper => {
746 const mutableSnapshot = new MutableSnapshot(this._store.getState().currentTree);
747 await mapper(mutableSnapshot);
748 const newState = mutableSnapshot.getStore_INTERNAL().getState().currentTree;
749 return cloneSnapshot(newState);
750 });
751
752 this._store = makeStore(treeState);
753 }
754
755 getStore_INTERNAL() {
756 return this._store;
757 }
758
759}
760
761function cloneTreeState(treeState) {
762 return {
763 transactionMetadata: { ...treeState.transactionMetadata
764 },
765 atomValues: new Map(treeState.atomValues),
766 nonvalidatedAtoms: new Map(treeState.nonvalidatedAtoms),
767 dirtyAtoms: new Set(treeState.dirtyAtoms),
768 nodeDeps: new Map(treeState.nodeDeps),
769 nodeToNodeSubscriptions: Recoil_mapMap(treeState.nodeToNodeSubscriptions, keys => new Set(keys)),
770 nodeToComponentSubscriptions: new Map()
771 };
772} // Factory to build a fresh snapshot
773
774
775function freshSnapshot() {
776 return new Snapshot(makeEmptyTreeState$1());
777} // Factory to clone a snapahot state
778
779
780function cloneSnapshot(treeState) {
781 return new Snapshot(cloneTreeState(treeState));
782}
783
784class MutableSnapshot extends Snapshot {
785 constructor(treeState) {
786 super(cloneTreeState(treeState));
787
788 _defineProperty(this, "set", (recoilState, newValueOrUpdater) => {
789 const store = this.getStore_INTERNAL();
790 const newValue = valueFromValueOrUpdater$1(store, recoilState, newValueOrUpdater);
791 setRecoilValue$1(store, recoilState, newValue);
792 });
793
794 _defineProperty(this, "reset", recoilState => setRecoilValue$1(this.getStore_INTERNAL(), recoilState, DEFAULT_VALUE$1));
795 } // We want to allow the methods to be destructured and used as accessors
796 // eslint-disable-next-line fb-www/extra-arrow-initializer
797
798
799}
800
801var Recoil_Snapshot = {
802 Snapshot,
803 MutableSnapshot,
804 freshSnapshot,
805 cloneSnapshot
806};
807
808var Recoil_Snapshot_1 = Recoil_Snapshot.Snapshot;
809var Recoil_Snapshot_2 = Recoil_Snapshot.MutableSnapshot;
810var Recoil_Snapshot_3 = Recoil_Snapshot.freshSnapshot;
811var Recoil_Snapshot_4 = Recoil_Snapshot.cloneSnapshot;
812
813var Recoil_Snapshot$1 = /*#__PURE__*/Object.freeze({
814 __proto__: null,
815 Snapshot: Recoil_Snapshot_1,
816 MutableSnapshot: Recoil_Snapshot_2,
817 freshSnapshot: Recoil_Snapshot_3,
818 cloneSnapshot: Recoil_Snapshot_4
819});
820
821/**
822 * Copyright (c) Facebook, Inc. and its affiliates.
823 *
824 * This source code is licensed under the MIT license found in the
825 * LICENSE file in the root directory of this source tree.
826 *
827 * @emails oncall+recoil
828 *
829 * @format
830 */
831
832function nullthrows(x, message) {
833 if (x != null) {
834 return x;
835 }
836
837 throw new Error(message !== null && message !== void 0 ? message : 'Got unexpected null or undefined');
838}
839
840var Recoil_nullthrows = nullthrows;
841
842const {
843 useContext,
844 useEffect,
845 useRef,
846 useState
847} = react;
848
849
850
851const {
852 fireNodeSubscriptions: fireNodeSubscriptions$1,
853 setNodeValue: setNodeValue$2,
854 setUnvalidatedAtomValue: setUnvalidatedAtomValue$2
855} = Recoil_FunctionalCore;
856
857const {
858 freshSnapshot: freshSnapshot$1
859} = Recoil_Snapshot$1;
860
861const {
862 makeEmptyStoreState: makeEmptyStoreState$1,
863 makeStoreState: makeStoreState$2
864} = Recoil_State;
865
866
867
868function notInAContext() {
869 throw new Error('This component must be used inside a <RecoilRoot> component.');
870}
871
872const defaultStore = Object.freeze({
873 getState: notInAContext,
874 replaceState: notInAContext,
875 subscribeToTransactions: notInAContext,
876 addTransactionMetadata: notInAContext,
877 fireNodeSubscriptions: notInAContext
878});
879
880function startNextTreeIfNeeded(storeState) {
881 if (storeState.nextTree === null) {
882 storeState.nextTree = { ...storeState.currentTree,
883 dirtyAtoms: new Set(),
884 transactionMetadata: {}
885 };
886 }
887}
888
889const AppContext = react.createContext({
890 current: defaultStore
891});
892
893const useStoreRef = () => useContext(AppContext);
894/*
895 * The purpose of the Batcher is to observe when React batches end so that
896 * Recoil state changes can be batched. Whenever Recoil state changes, we call
897 * setState on the batcher. Then we wait for that change to be committed, which
898 * signifies the end of the batch. That's when we respond to the Recoil change.
899 */
900
901
902function Batcher(props) {
903 const storeRef = useStoreRef();
904 const [_, setState] = useState([]);
905 props.setNotifyBatcherOfChange(() => setState({}));
906 useEffect(() => {
907 // enqueueExecution runs this function immediately; it is only used to
908 // manipulate the order of useEffects during tests, since React seems to
909 // call useEffect in an unpredictable order sometimes.
910 Recoil_Queue.enqueueExecution('Batcher', () => {
911 const storeState = storeRef.current.getState();
912 const {
913 nextTree
914 } = storeState; // Ignore commits that are not because of Recoil transactions -- namely,
915 // because something above RecoilRoot re-rendered:
916
917 if (nextTree === null) {
918 return;
919 } // Inform transaction subscribers of the transaction:
920
921
922 const dirtyAtoms = nextTree.dirtyAtoms;
923
924 if (dirtyAtoms.size) {
925 storeState.transactionSubscriptions.forEach(sub => sub(storeRef.current));
926 } // Inform components that depend on dirty atoms of the transaction:
927 // FIXME why is this StoreState but dirtyAtoms is TreeState? Seems like they should be the same.
928
929
930 storeState.queuedComponentCallbacks.forEach(cb => cb(nextTree));
931 storeState.queuedComponentCallbacks.splice(0, storeState.queuedComponentCallbacks.length); // nextTree is now committed -- note that copying and reset occurs when
932 // a transaction begins, in startNextTreeIfNeeded:
933
934 storeState.currentTree = nextTree;
935 storeState.nextTree = null;
936 });
937 });
938 return null;
939}
940
941{
942 if (typeof window !== 'undefined' && !window.$recoilDebugStates) {
943 window.$recoilDebugStates = [];
944 }
945}
946
947function initialStoreState_DEPRECATED(store, initializeState) {
948 const initial = makeEmptyStoreState$1();
949 initializeState({
950 set: (atom, value) => {
951 initial.currentTree = setNodeValue$2(store, initial.currentTree, atom.key, value)[0];
952 },
953 setUnvalidatedAtomValues: atomValues => {
954 atomValues.forEach((v, k) => {
955 initial.currentTree = setUnvalidatedAtomValue$2(initial.currentTree, k, v);
956 });
957 }
958 });
959 return initial;
960}
961
962function initialStoreState(initializeState) {
963 const snapshot = freshSnapshot$1().map(initializeState);
964 return makeStoreState$2(snapshot.getStore_INTERNAL().getState().currentTree);
965}
966
967let nextID = 0;
968
969function RecoilRoot({
970 initializeState_DEPRECATED,
971 initializeState,
972 children
973}) {
974 let storeState; // eslint-disable-line prefer-const
975
976 const subscribeToTransactions = callback => {
977 const id = nextID++;
978 storeRef.current.getState().transactionSubscriptions.set(id, callback);
979 return {
980 release: () => {
981 storeRef.current.getState().transactionSubscriptions.delete(id);
982 }
983 };
984 };
985
986 const addTransactionMetadata = metadata => {
987 startNextTreeIfNeeded(storeRef.current.getState());
988
989 for (const k of Object.keys(metadata)) {
990 Recoil_nullthrows(storeRef.current.getState().nextTree).transactionMetadata[k] = metadata[k];
991 }
992 };
993
994 function fireNodeSubscriptionsForStore(updatedNodes, when) {
995 fireNodeSubscriptions$1(storeRef.current, updatedNodes, when);
996 }
997
998 const replaceState = replacer => {
999 const storeState = storeRef.current.getState();
1000 startNextTreeIfNeeded(storeState); // Use replacer to get the next state:
1001
1002 const nextTree = Recoil_nullthrows(storeState.nextTree);
1003 const replaced = replacer(nextTree);
1004
1005 if (replaced === nextTree) {
1006 return;
1007 }
1008
1009 {
1010 if (typeof window !== 'undefined') {
1011 window.$recoilDebugStates.push(replaced); // TODO this shouldn't happen here because it's not batched
1012 }
1013 } // Save changes to nextTree and schedule a React update:
1014
1015
1016 storeState.nextTree = replaced;
1017 Recoil_nullthrows(notifyBatcherOfChange.current)();
1018 };
1019
1020 const notifyBatcherOfChange = useRef(null);
1021
1022 function setNotifyBatcherOfChange(x) {
1023 notifyBatcherOfChange.current = x;
1024 }
1025
1026 const store = {
1027 getState: () => storeState.current,
1028 replaceState,
1029 subscribeToTransactions,
1030 addTransactionMetadata,
1031 fireNodeSubscriptions: fireNodeSubscriptionsForStore
1032 };
1033 const storeRef = useRef(store);
1034 storeState = useRef(initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(store, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$1());
1035 return /*#__PURE__*/react.createElement(AppContext.Provider, {
1036 value: storeRef
1037 }, /*#__PURE__*/react.createElement(Batcher, {
1038 setNotifyBatcherOfChange: setNotifyBatcherOfChange
1039 }), children);
1040}
1041
1042var Recoil_RecoilRoot_react = {
1043 useStoreRef,
1044 RecoilRoot
1045};
1046
1047/**
1048 * Copyright (c) Facebook, Inc. and its affiliates.
1049 *
1050 * This source code is licensed under the MIT license found in the
1051 * LICENSE file in the root directory of this source tree.
1052 *
1053 * @emails oncall+recoil
1054 *
1055 * @format
1056 */
1057/**
1058 * Returns a set containing all of the values from the first set that are not
1059 * present in any of the subsequent sets.
1060 *
1061 * Note: this is written procedurally (i.e., without filterSet) for performant
1062 * use in tight loops.
1063 */
1064
1065function differenceSets(set, ...setsWithValuesToRemove) {
1066 const ret = new Set();
1067
1068 FIRST: for (const value of set) {
1069 for (const otherSet of setsWithValuesToRemove) {
1070 if (otherSet.has(value)) {
1071 continue FIRST;
1072 }
1073 }
1074
1075 ret.add(value);
1076 }
1077
1078 return ret;
1079}
1080
1081var Recoil_differenceSets = differenceSets;
1082
1083/**
1084 * Copyright (c) Facebook, Inc. and its affiliates.
1085 *
1086 * This source code is licensed under the MIT license found in the
1087 * LICENSE file in the root directory of this source tree.
1088 *
1089 * @emails oncall+recoil
1090 *
1091 * @format
1092 */
1093/**
1094 * Returns a map containing all of the keys + values from the original map where
1095 * the given callback returned true.
1096 */
1097
1098function filterMap(map, callback) {
1099 const result = new Map();
1100
1101 for (const [key, value] of map) {
1102 if (callback(value, key)) {
1103 result.set(key, value);
1104 }
1105 }
1106
1107 return result;
1108}
1109
1110var Recoil_filterMap = filterMap;
1111
1112/**
1113 * Copyright (c) Facebook, Inc. and its affiliates.
1114 *
1115 * This source code is licensed under the MIT license found in the
1116 * LICENSE file in the root directory of this source tree.
1117 *
1118 * Returns the set of values that are present in all the given sets, preserving
1119 * the order of the first set.
1120 *
1121 * Note: this is written procedurally (i.e., without filterSet) for performant
1122 * use in tight loops.
1123 *
1124 * @emails oncall+recoil
1125 *
1126 * @format
1127 */
1128
1129function intersectSets(first, ...rest) {
1130 const ret = new Set();
1131
1132 FIRST: for (const value of first) {
1133 for (const otherSet of rest) {
1134 if (!otherSet.has(value)) {
1135 continue FIRST;
1136 }
1137 }
1138
1139 ret.add(value);
1140 }
1141
1142 return ret;
1143}
1144
1145var Recoil_intersectSets = intersectSets;
1146
1147/**
1148 * Copyright (c) Facebook, Inc. and its affiliates.
1149 *
1150 * This source code is licensed under the MIT license found in the
1151 * LICENSE file in the root directory of this source tree.
1152 *
1153 * @emails oncall+recoil
1154 *
1155 * @format
1156 */
1157// prettier-ignore
1158
1159function invariant(condition, message) {
1160 // @oss-only
1161 if (!condition) {
1162 // @oss-only
1163 throw new Error(message); // @oss-only
1164 } // @oss-only
1165
1166} // @oss-only
1167
1168
1169var Recoil_invariant = invariant;
1170
1171/**
1172 * Copyright (c) Facebook, Inc. and its affiliates.
1173 *
1174 * This source code is licensed under the MIT license found in the
1175 * LICENSE file in the root directory of this source tree.
1176 *
1177 * @emails oncall+recoil
1178 *
1179 * @format
1180 */
1181
1182function mergeMaps(...maps) {
1183 const result = new Map();
1184
1185 for (let i = 0; i < maps.length; i++) {
1186 const iterator = maps[i].keys();
1187 let nextKey;
1188
1189 while (!(nextKey = iterator.next()).done) {
1190 // $FlowFixMe - map/iterator knows nothing about flow types
1191 result.set(nextKey.value, maps[i].get(nextKey.value));
1192 }
1193 }
1194 /* $FlowFixMe(>=0.66.0 site=www,mobile) This comment suppresses an error
1195 * found when Flow v0.66 was deployed. To see the error delete this comment
1196 * and run Flow. */
1197
1198
1199 return result;
1200}
1201
1202var Recoil_mergeMaps = mergeMaps;
1203
1204const {
1205 useCallback,
1206 useEffect: useEffect$1,
1207 useMemo,
1208 useRef: useRef$1,
1209 useState: useState$1
1210} = react;
1211
1212
1213
1214const {
1215 peekNodeLoadable: peekNodeLoadable$2,
1216 setNodeValue: setNodeValue$3
1217} = Recoil_FunctionalCore;
1218
1219const {
1220 DEFAULT_VALUE: DEFAULT_VALUE$2,
1221 getNode: getNode$2,
1222 nodes: nodes$1
1223} = Recoil_Node;
1224
1225const {
1226 useStoreRef: useStoreRef$1
1227} = Recoil_RecoilRoot_react;
1228
1229const {
1230 isRecoilValue: isRecoilValue$1
1231} = Recoil_RecoilValue$1;
1232
1233const {
1234 AbstractRecoilValue: AbstractRecoilValue$2,
1235 getRecoilValueAsLoadable: getRecoilValueAsLoadable$2,
1236 setRecoilValue: setRecoilValue$2,
1237 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$1,
1238 subscribeToRecoilValue: subscribeToRecoilValue$1,
1239 valueFromValueOrUpdater: valueFromValueOrUpdater$2
1240} = Recoil_RecoilValueInterface;
1241
1242const {
1243 Snapshot: Snapshot$1,
1244 cloneSnapshot: cloneSnapshot$1
1245} = Recoil_Snapshot$1;
1246
1247const {
1248 setByAddingToSet: setByAddingToSet$2
1249} = Recoil_CopyOnWrite;
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269function cloneState_DEPRECATED(state) {
1270 return {
1271 transactionMetadata: { ...state.transactionMetadata
1272 },
1273 atomValues: new Map(state.atomValues),
1274 nonvalidatedAtoms: new Map(state.nonvalidatedAtoms),
1275 dirtyAtoms: new Set(state.dirtyAtoms),
1276 nodeDeps: new Map(state.nodeDeps),
1277 nodeToNodeSubscriptions: Recoil_mapMap(state.nodeToNodeSubscriptions, keys => new Set(keys)),
1278 nodeToComponentSubscriptions: Recoil_mapMap(state.nodeToComponentSubscriptions, subsByAtom => new Map(subsByAtom))
1279 };
1280}
1281
1282function handleLoadable(loadable, atom, storeRef) {
1283 // We can't just throw the promise we are waiting on to Suspense. If the
1284 // upstream dependencies change it may produce a state in which the component
1285 // can render, but it would still be suspended on a Promise that may never resolve.
1286 if (loadable.state === 'hasValue') {
1287 return loadable.contents;
1288 } else if (loadable.state === 'loading') {
1289 const promise = new Promise(resolve => {
1290 storeRef.current.getState().suspendedComponentResolvers.add(resolve);
1291 });
1292 throw promise;
1293 } else if (loadable.state === 'hasError') {
1294 throw loadable.contents;
1295 } else {
1296 throw new Error(`Invalid value of loadable atom "${atom.key}"`);
1297 }
1298}
1299
1300function validateRecoilValue(recoilValue, hookName) {
1301 if (!isRecoilValue$1(recoilValue)) {
1302 throw new Error(`Invalid argument to ${hookName}: expected an atom or selector but got ${String(recoilValue)}`);
1303 }
1304}
1305
1306function useInterface() {
1307 const storeRef = useStoreRef$1();
1308 const [_, forceUpdate] = useState$1([]);
1309 const recoilValuesUsed = useRef$1(new Set());
1310 recoilValuesUsed.current = new Set(); // Track the RecoilValues used just during this render
1311
1312 const previousSubscriptions = useRef$1(new Set());
1313 const subscriptions = useRef$1(new Map());
1314 const unsubscribeFrom = useCallback(key => {
1315 const sub = subscriptions.current.get(key);
1316
1317 if (sub) {
1318 sub.release(storeRef.current);
1319 subscriptions.current.delete(key);
1320 }
1321 }, [storeRef, subscriptions]);
1322 useEffect$1(() => {
1323 const store = storeRef.current;
1324
1325 function updateState(_state, key) {
1326 if (!subscriptions.current.has(key)) {
1327 return;
1328 }
1329
1330 forceUpdate([]);
1331 }
1332
1333 Recoil_differenceSets(recoilValuesUsed.current, previousSubscriptions.current).forEach(key => {
1334 if (subscriptions.current.has(key)) {
1335 Recoil_expectationViolation(`Double subscription to RecoilValue "${key}"`);
1336 return;
1337 }
1338
1339 const sub = subscribeToRecoilValue$1(store, new AbstractRecoilValue$2(key), state => {
1340 Recoil_Tracing.trace('RecoilValue subscription fired', key, () => {
1341 updateState(state, key);
1342 });
1343 });
1344 subscriptions.current.set(key, sub);
1345 Recoil_Tracing.trace('initial update on subscribing', key, () => {
1346 updateState(store.getState(), key);
1347 });
1348 });
1349 Recoil_differenceSets(previousSubscriptions.current, recoilValuesUsed.current).forEach(key => {
1350 unsubscribeFrom(key);
1351 });
1352 previousSubscriptions.current = recoilValuesUsed.current;
1353 });
1354 useEffect$1(() => {
1355 const subs = subscriptions.current;
1356 return () => subs.forEach((_, key) => unsubscribeFrom(key));
1357 }, [unsubscribeFrom]);
1358 return useMemo(() => {
1359 function useSetRecoilState(recoilState) {
1360 {
1361 validateRecoilValue(recoilState, 'useSetRecoilState');
1362 }
1363
1364 return newValueOrUpdater => {
1365 const newValue = valueFromValueOrUpdater$2(storeRef.current, recoilState, newValueOrUpdater);
1366 setRecoilValue$2(storeRef.current, recoilState, newValue);
1367 };
1368 }
1369
1370 function useResetRecoilState(recoilState) {
1371 {
1372 validateRecoilValue(recoilState, 'useResetRecoilState');
1373 }
1374
1375 return () => setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
1376 }
1377
1378 function useRecoilValueLoadable(recoilValue) {
1379 {
1380 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
1381 }
1382
1383 if (!recoilValuesUsed.current.has(recoilValue.key)) {
1384 recoilValuesUsed.current = setByAddingToSet$2(recoilValuesUsed.current, recoilValue.key);
1385 } // TODO Restore optimization to memoize lookup
1386
1387
1388 return getRecoilValueAsLoadable$2(storeRef.current, recoilValue);
1389 }
1390
1391 function useRecoilValue(recoilValue) {
1392 {
1393 validateRecoilValue(recoilValue, 'useRecoilValue');
1394 }
1395
1396 const loadable = useRecoilValueLoadable(recoilValue);
1397 return handleLoadable(loadable, recoilValue, storeRef);
1398 }
1399
1400 function useRecoilState(recoilState) {
1401 {
1402 validateRecoilValue(recoilState, 'useRecoilState');
1403 }
1404
1405 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
1406 }
1407
1408 function useRecoilStateLoadable(recoilState) {
1409 {
1410 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
1411 }
1412
1413 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
1414 }
1415
1416 return {
1417 getRecoilValue: useRecoilValue,
1418 getRecoilValueLoadable: useRecoilValueLoadable,
1419 getRecoilState: useRecoilState,
1420 getRecoilStateLoadable: useRecoilStateLoadable,
1421 getSetRecoilState: useSetRecoilState,
1422 getResetRecoilState: useResetRecoilState
1423 };
1424 }, [recoilValuesUsed, storeRef]);
1425}
1426/**
1427 Returns the value represented by the RecoilValue.
1428 If the value is pending, it will throw a Promise to suspend the component,
1429 if the value is an error it will throw it for the nearest React error boundary.
1430 This will also subscribe the component for any updates in the value.
1431 */
1432
1433
1434function useRecoilValue(recoilValue) {
1435 return useInterface().getRecoilValue(recoilValue);
1436}
1437/**
1438 Like useRecoilValue(), but either returns the value if available or
1439 just undefined if not available for any reason, such as pending or error.
1440*/
1441
1442
1443function useRecoilValueLoadable(recoilValue) {
1444 return useInterface().getRecoilValueLoadable(recoilValue);
1445}
1446/**
1447 Returns a function that allows the value of a RecoilState to be updated, but does
1448 not subscribe the component to changes to that RecoilState.
1449*/
1450
1451
1452function useSetRecoilState(recoilState) {
1453 return useCallback(useInterface().getSetRecoilState(recoilState), [recoilState]);
1454}
1455/**
1456 Returns a function that will reset the value of a RecoilState to its default
1457*/
1458
1459
1460function useResetRecoilState(recoilState) {
1461 return useCallback(useInterface().getResetRecoilState(recoilState), [recoilState]);
1462}
1463/**
1464 Equivalent to useState(). Allows the value of the RecoilState to be read and written.
1465 Subsequent updates to the RecoilState will cause the component to re-render. If the
1466 RecoilState is pending, this will suspend the component and initiate the
1467 retrieval of the value. If evaluating the RecoilState resulted in an error, this will
1468 throw the error so that the nearest React error boundary can catch it.
1469*/
1470
1471
1472function useRecoilState(recoilState) {
1473 const recoilInterface = useInterface();
1474 const [value] = recoilInterface.getRecoilState(recoilState);
1475 const setValue = useCallback(recoilInterface.getSetRecoilState(recoilState), [recoilState]);
1476 return [value, setValue];
1477}
1478/**
1479 Like useRecoilState(), but does not cause Suspense or React error handling. Returns
1480 an object that indicates whether the RecoilState is available, pending, or
1481 unavailable due to an error.
1482*/
1483
1484
1485function useRecoilStateLoadable(recoilState) {
1486 const recoilInterface = useInterface();
1487 const [value] = recoilInterface.getRecoilStateLoadable(recoilState);
1488 const setValue = useCallback(recoilInterface.getSetRecoilState(recoilState), [recoilState]);
1489 return [value, setValue];
1490}
1491
1492function useTransactionSubscription(callback) {
1493 const storeRef = useStoreRef$1();
1494 useEffect$1(() => {
1495 const sub = storeRef.current.subscribeToTransactions(callback);
1496 return sub.release;
1497 }, [callback, storeRef]);
1498} // TODO instead of force update can put snapshot into local state
1499
1500
1501function useTreeStateClone_DEPRECATED() {
1502 const [_, setState] = useState$1(0);
1503 const forceUpdate = useCallback(() => setState(x => x + 1), []);
1504 useTransactionSubscription(forceUpdate);
1505 const storeRef = useStoreRef$1();
1506 return cloneState_DEPRECATED(storeRef.current.getState().currentTree);
1507}
1508
1509function useSnapshotWithStateChange_DEPRECATED(transaction) {
1510 const storeRef = useStoreRef$1();
1511 let snapshot = useTreeStateClone_DEPRECATED();
1512
1513 const update = ({
1514 key
1515 }, updater) => {
1516 [snapshot] = setNodeValue$3(storeRef.current, snapshot, key, peekNodeLoadable$2(storeRef.current, snapshot, key).map(updater));
1517 };
1518
1519 transaction(update);
1520 const atomValues = Recoil_mapMap(snapshot.atomValues, v => v.contents); // Only report atoms, not selectors
1521
1522 const updatedAtoms = Recoil_intersectSets(snapshot.dirtyAtoms, new Set(atomValues.keys()));
1523 return {
1524 atomValues,
1525 updatedAtoms
1526 };
1527}
1528
1529function externallyVisibleAtomValuesInState(state) {
1530 const atomValues = state.atomValues;
1531 const persistedAtomContentsValues = Recoil_mapMap(Recoil_filterMap(atomValues, (v, k) => {
1532 var _node$options;
1533
1534 const node = getNode$2(k);
1535 const persistence = (_node$options = node.options) === null || _node$options === void 0 ? void 0 : _node$options.persistence_UNSTABLE;
1536 return persistence != null && persistence.type !== 'none' && v.state === 'hasValue';
1537 }), v => v.contents); // Merge in nonvalidated atoms; we may not have defs for them but they will
1538 // all have persistence on or they wouldn't be there in the first place.
1539
1540 return Recoil_mergeMaps(state.nonvalidatedAtoms, persistedAtomContentsValues);
1541}
1542
1543/**
1544 Calls the given callback after any atoms have been modified and the consequent
1545 component re-renders have been committed. This is intended for persisting
1546 the values of the atoms to storage. The stored values can then be restored
1547 using the useSetUnvalidatedAtomValues hook.
1548
1549 The callback receives the following info:
1550
1551 atomValues: The current value of every atom that is both persistable (persistence
1552 type not set to 'none') and whose value is available (not in an
1553 error or loading state).
1554
1555 previousAtomValues: The value of every persistable and available atom before
1556 the transaction began.
1557
1558 atomInfo: A map containing the persistence settings for each atom. Every key
1559 that exists in atomValues will also exist in atomInfo.
1560
1561 modifiedAtoms: The set of atoms that were written to during the transaction.
1562
1563 transactionMetadata: Arbitrary information that was added via the
1564 useSetUnvalidatedAtomValues hook. Useful for ignoring the useSetUnvalidatedAtomValues
1565 transaction, to avoid loops.
1566*/
1567function useTransactionObservation_DEPRECATED(callback) {
1568 useTransactionSubscription(useCallback(store => {
1569 const previousState = store.getState().currentTree;
1570 let nextState = store.getState().nextTree;
1571
1572 if (!nextState) {
1573 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
1574 nextState = store.getState().currentTree; // attempt to trundle on
1575 }
1576
1577 const atomValues = externallyVisibleAtomValuesInState(nextState);
1578 const previousAtomValues = externallyVisibleAtomValuesInState(previousState);
1579 const atomInfo = Recoil_mapMap(nodes$1, node => {
1580 var _node$options$persist, _node$options2, _node$options2$persis, _node$options$persist2, _node$options3, _node$options3$persis;
1581
1582 return {
1583 persistence_UNSTABLE: {
1584 type: (_node$options$persist = (_node$options2 = node.options) === null || _node$options2 === void 0 ? void 0 : (_node$options2$persis = _node$options2.persistence_UNSTABLE) === null || _node$options2$persis === void 0 ? void 0 : _node$options2$persis.type) !== null && _node$options$persist !== void 0 ? _node$options$persist : 'none',
1585 backButton: (_node$options$persist2 = (_node$options3 = node.options) === null || _node$options3 === void 0 ? void 0 : (_node$options3$persis = _node$options3.persistence_UNSTABLE) === null || _node$options3$persis === void 0 ? void 0 : _node$options3$persis.backButton) !== null && _node$options$persist2 !== void 0 ? _node$options$persist2 : false
1586 }
1587 };
1588 });
1589 const modifiedAtoms = new Set(nextState.dirtyAtoms);
1590 callback({
1591 atomValues,
1592 previousAtomValues,
1593 atomInfo,
1594 modifiedAtoms,
1595 transactionMetadata: { ...nextState.transactionMetadata
1596 }
1597 });
1598 }, [callback]));
1599}
1600
1601function useRecoilTransactionObserver(callback) {
1602 useTransactionSubscription(useCallback(store => {
1603 const previousState = store.getState().currentTree;
1604 let nextState = store.getState().nextTree;
1605
1606 if (!nextState) {
1607 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
1608 nextState = previousState; // attempt to trundle on
1609 }
1610
1611 callback({
1612 snapshot: cloneSnapshot$1(nextState),
1613 previousSnapshot: cloneSnapshot$1(previousState)
1614 });
1615 }, [callback]));
1616} // Return a snapshot of the current state and subscribe to all state changes
1617
1618
1619function useRecoilSnapshot() {
1620 const store = useStoreRef$1();
1621 const [snapshot, setSnapshot] = useState$1(() => cloneSnapshot$1(store.current.getState().currentTree));
1622 useTransactionSubscription(useCallback(store => {
1623 var _store$getState$nextT;
1624
1625 return setSnapshot(cloneSnapshot$1((_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree));
1626 }, []));
1627 return snapshot;
1628}
1629
1630function useGoToSnapshot_DEPRECATED() {
1631 const storeRef = useStoreRef$1();
1632 return snapshot => {
1633 reactDom.unstable_batchedUpdates(() => {
1634 snapshot.updatedAtoms.forEach(key => {
1635 setRecoilValue$2(storeRef.current, new AbstractRecoilValue$2(key), snapshot.atomValues.get(key));
1636 });
1637 });
1638 };
1639}
1640
1641function useGotoRecoilSnapshot() {
1642 const storeRef = useStoreRef$1();
1643 return useCallback(snapshot => {
1644 reactDom.unstable_batchedUpdates(() => {
1645 storeRef.current.replaceState(prevState => {
1646 const nextState = snapshot.getStore_INTERNAL().getState().currentTree; // Fire subscriptions for any atoms that changed values
1647
1648 const updatedKeys = new Set(); // Going through both seems to be more efficient than constructing a union set of keys
1649
1650 for (const keys of [prevState.atomValues.keys(), nextState.atomValues.keys()]) {
1651 for (const key of keys) {
1652 var _prevState$atomValues, _nextState$atomValues;
1653
1654 if (((_prevState$atomValues = prevState.atomValues.get(key)) === null || _prevState$atomValues === void 0 ? void 0 : _prevState$atomValues.contents) !== ((_nextState$atomValues = nextState.atomValues.get(key)) === null || _nextState$atomValues === void 0 ? void 0 : _nextState$atomValues.contents)) {
1655 updatedKeys.add(key);
1656 }
1657 }
1658 }
1659
1660 storeRef.current.fireNodeSubscriptions(updatedKeys, 'enqueue');
1661 return { ...nextState,
1662 nodeToComponentSubscriptions: prevState.nodeToComponentSubscriptions
1663 };
1664 });
1665 });
1666 }, [storeRef]);
1667}
1668
1669function useSetUnvalidatedAtomValues() {
1670 const storeRef = useStoreRef$1();
1671 return (values, transactionMetadata = {}) => {
1672 reactDom.unstable_batchedUpdates(() => {
1673 storeRef.current.addTransactionMetadata(transactionMetadata);
1674 values.forEach((value, key) => setUnvalidatedRecoilValue$1(storeRef.current, new AbstractRecoilValue$2(key), value));
1675 });
1676 };
1677}
1678
1679class Sentinel {}
1680
1681const SENTINEL = new Sentinel();
1682
1683function useRecoilCallback(fn, deps) {
1684 const storeRef = useStoreRef$1();
1685 const gotoSnapshot = useGotoRecoilSnapshot();
1686 return useCallback((...args) => {
1687 // Use currentTree for the snapshot to show the currently committed stable state
1688 const snapshot = cloneSnapshot$1(storeRef.current.getState().currentTree);
1689
1690 function set(recoilState, newValueOrUpdater) {
1691 const newValue = valueFromValueOrUpdater$2(storeRef.current, recoilState, newValueOrUpdater);
1692 setRecoilValue$2(storeRef.current, recoilState, newValue);
1693 }
1694
1695 function reset(recoilState) {
1696 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
1697 }
1698
1699 let ret = SENTINEL;
1700 reactDom.unstable_batchedUpdates(() => {
1701 // flowlint-next-line unclear-type:off
1702 ret = fn({
1703 set,
1704 reset,
1705 snapshot,
1706 gotoSnapshot
1707 })(...args);
1708 });
1709 !!(ret instanceof Sentinel) ? Recoil_invariant(false, 'unstable_batchedUpdates should return immediately') : void 0;
1710 return ret;
1711 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
1712 );
1713}
1714
1715var Recoil_Hooks = {
1716 useRecoilCallback,
1717 useRecoilValue,
1718 useRecoilValueLoadable,
1719 useRecoilState,
1720 useRecoilStateLoadable,
1721 useSetRecoilState,
1722 useResetRecoilState,
1723 useRecoilInterface: useInterface,
1724 useSnapshotWithStateChange_DEPRECATED,
1725 useTransactionSubscription_DEPRECATED: useTransactionSubscription,
1726 useTransactionObservation_DEPRECATED,
1727 useRecoilTransactionObserver,
1728 useRecoilSnapshot,
1729 useGoToSnapshot_DEPRECATED,
1730 useGotoRecoilSnapshot,
1731 useSetUnvalidatedAtomValues
1732};
1733
1734/**
1735 * Copyright (c) Facebook, Inc. and its affiliates.
1736 *
1737 * This source code is licensed under the MIT license found in the
1738 * LICENSE file in the root directory of this source tree.
1739 *
1740 * @emails oncall+recoil
1741 *
1742 * @format
1743 */
1744
1745// Split declaration and implementation to allow this function to pretend to
1746// check for actual instance of Promise instead of something with a `then`
1747// method.
1748// eslint-disable-next-line no-redeclare
1749function isPromise(p) {
1750 return !!p && typeof p.then === 'function';
1751}
1752
1753var Recoil_isPromise = isPromise;
1754
1755// TODO Convert Loadable to a Class to allow for runtime type detection.
1756// Containing static factories of withValue(), withError(), withPromise(), and all()
1757
1758
1759const loadableAccessors = {
1760 getValue() {
1761 if (this.state !== 'hasValue') {
1762 throw this.contents; // Throw Error, or Promise for the loading state
1763 }
1764
1765 return this.contents;
1766 },
1767
1768 toPromise() {
1769 return this.state === 'hasValue' ? Promise.resolve(this.contents) : this.state === 'hasError' ? Promise.reject(this.contents) : this.contents;
1770 },
1771
1772 valueMaybe() {
1773 return this.state === 'hasValue' ? this.contents : undefined;
1774 },
1775
1776 valueOrThrow() {
1777 if (this.state !== 'hasValue') {
1778 throw new Error(`Loadable expected value, but in "${this.state}" state`);
1779 }
1780
1781 return this.contents;
1782 },
1783
1784 errorMaybe() {
1785 return this.state === 'hasError' ? this.contents : undefined;
1786 },
1787
1788 errorOrThrow() {
1789 if (this.state !== 'hasError') {
1790 throw new Error(`Loadable expected error, but in "${this.state}" state`);
1791 }
1792
1793 return this.contents;
1794 },
1795
1796 promiseMaybe() {
1797 return this.state === 'loading' ? this.contents : undefined;
1798 },
1799
1800 promiseOrThrow() {
1801 if (this.state !== 'loading') {
1802 throw new Error(`Loadable expected promise, but in "${this.state}" state`);
1803 }
1804
1805 return this.contents;
1806 },
1807
1808 // TODO Unit tests
1809 // TODO Convert Loadable to a Class to better support chaining
1810 // by returning a Loadable from a map function
1811 map(map) {
1812 if (this.state === 'hasError') {
1813 return this;
1814 }
1815
1816 if (this.state === 'hasValue') {
1817 try {
1818 const next = map(this.contents); // TODO if next instanceof Loadable, then return next
1819
1820 return Recoil_isPromise(next) ? loadableWithPromise(next) : loadableWithValue(next);
1821 } catch (e) {
1822 return Recoil_isPromise(e) ? // If we "suspended", then try again.
1823 // errors and subsequent retries will be handled in 'loading' case
1824 loadableWithPromise(e.next(() => map(this.contents))) : loadableWithError(e);
1825 }
1826 }
1827
1828 if (this.state === 'loading') {
1829 return loadableWithPromise(this.contents // TODO if map returns a loadable, then return the value or promise or throw the error
1830 .then(map).catch(e => {
1831 if (Recoil_isPromise(e)) {
1832 // we were "suspended," try again
1833 return e.then(() => map(this.contents));
1834 }
1835
1836 throw e;
1837 }));
1838 }
1839
1840 throw new Error('Invalid Loadable state');
1841 }
1842
1843};
1844
1845function loadableWithValue(value) {
1846 // Build objects this way since Flow doesn't support disjoint unions for class properties
1847 return Object.freeze({
1848 state: 'hasValue',
1849 contents: value,
1850 ...loadableAccessors
1851 });
1852}
1853
1854function loadableWithError(error) {
1855 return Object.freeze({
1856 state: 'hasError',
1857 contents: error,
1858 ...loadableAccessors
1859 });
1860}
1861
1862function loadableWithPromise(promise) {
1863 return Object.freeze({
1864 state: 'loading',
1865 contents: promise,
1866 ...loadableAccessors
1867 });
1868}
1869
1870function loadableLoading() {
1871 return loadableWithPromise(new Promise(() => {}));
1872}
1873
1874function loadableAll(inputs) {
1875 return inputs.every(i => i.state === 'hasValue') ? loadableWithValue(inputs.map(i => i.contents)) : inputs.some(i => i.state === 'hasError') ? loadableWithError( // $FlowIssue #44070740 Array.find should refine parameter
1876 Recoil_nullthrows(inputs.find(i => i.state === 'hasError'), 'Invalid loadable passed to loadableAll').contents) : loadableWithPromise( Promise.all(inputs.map(i => i.contents)));
1877}
1878
1879var Recoil_Loadable = {
1880 loadableWithValue,
1881 loadableWithError,
1882 loadableWithPromise,
1883 loadableLoading,
1884 loadableAll
1885};
1886
1887/**
1888 * Copyright (c) Facebook, Inc. and its affiliates.
1889 *
1890 * This source code is licensed under the MIT license found in the
1891 * LICENSE file in the root directory of this source tree.
1892 *
1893 * @emails oncall+recoil
1894 *
1895 * @format
1896 */
1897
1898function isNode(object) {
1899 var _ownerDocument, _doc$defaultView;
1900
1901 if (typeof window === 'undefined') {
1902 return false;
1903 }
1904
1905 const doc = object != null ? (_ownerDocument = object.ownerDocument) !== null && _ownerDocument !== void 0 ? _ownerDocument : object : document;
1906 const defaultView = (_doc$defaultView = doc.defaultView) !== null && _doc$defaultView !== void 0 ? _doc$defaultView : window;
1907 return !!(object != null && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
1908}
1909
1910var Recoil_isNode = isNode;
1911
1912function shouldNotBeFrozen(value) {
1913 // Primitives and functions:
1914 if (value === null || typeof value !== 'object') {
1915 return true;
1916 } // React elements:
1917
1918
1919 switch (typeof value.$$typeof) {
1920 case 'symbol':
1921 return true;
1922
1923 case 'number':
1924 return true;
1925 } // Immutable structures:
1926
1927
1928 if (value['@@__IMMUTABLE_ITERABLE__@@'] != null || value['@@__IMMUTABLE_KEYED__@@'] != null || value['@@__IMMUTABLE_INDEXED__@@'] != null || value['@@__IMMUTABLE_ORDERED__@@'] != null || value['@@__IMMUTABLE_RECORD__@@'] != null) {
1929 return true;
1930 } // DOM nodes:
1931
1932
1933 if (Recoil_isNode(value)) {
1934 return true;
1935 }
1936
1937 if (Recoil_isPromise(value)) {
1938 return true;
1939 }
1940
1941 return false;
1942} // Recursively freeze a value to enforce it is read-only.
1943// This may also have minimal performance improvements for enumerating
1944// objects (based on browser implementations, of course)
1945
1946
1947function deepFreezeValue(value) {
1948 if (typeof value !== 'object' || shouldNotBeFrozen(value)) {
1949 return;
1950 }
1951
1952 Object.freeze(value); // Make all properties read-only
1953
1954 for (const key in value) {
1955 if (Object.prototype.hasOwnProperty.call(value, key)) {
1956 const prop = value[key]; // Prevent infinite recurssion for circular references.
1957
1958 if (typeof prop === 'object' && prop != null && !Object.isFrozen(prop)) {
1959 deepFreezeValue(prop);
1960 }
1961 }
1962 }
1963
1964 Object.seal(value); // This also makes existing properties non-configurable.
1965}
1966
1967var Recoil_deepFreezeValue = deepFreezeValue;
1968
1969/**
1970 * Copyright (c) Facebook, Inc. and its affiliates.
1971 *
1972 * This source code is licensed under the MIT license found in the
1973 * LICENSE file in the root directory of this source tree.
1974 *
1975 * Implements (a subset of) the interface of built-in Map but supports arrays as
1976 * keys. Two keys are equal if corresponding elements are equal according to the
1977 * equality semantics of built-in Map. Operations are at worst O(n*b) where n is
1978 * the array length and b is the complexity of the built-in operation.
1979 *
1980 * @emails oncall+recoil
1981 *
1982 * @format
1983 */
1984
1985const LEAF = Symbol('ArrayKeyedMap');
1986const emptyMap$1 = new Map();
1987
1988class ArrayKeyedMap {
1989 // @fb-only: _base: Map<any, any> = new Map();
1990 constructor(existing) {
1991 // $FlowOSSFixMe
1992 this._base = new Map(); // @oss-only
1993
1994 if (existing instanceof ArrayKeyedMap) {
1995 for (const [k, v] of existing.entries()) {
1996 this.set(k, v);
1997 }
1998 } else if (existing) {
1999 for (const [k, v] of existing) {
2000 this.set(k, v);
2001 }
2002 }
2003
2004 return this;
2005 }
2006
2007 get(key) {
2008 const ks = Array.isArray(key) ? key : [key]; // $FlowOSSFixMe
2009
2010 let map = this._base;
2011 ks.forEach(k => {
2012 var _map$get;
2013
2014 map = (_map$get = map.get(k)) !== null && _map$get !== void 0 ? _map$get : emptyMap$1;
2015 });
2016 return map === undefined ? undefined : map.get(LEAF);
2017 }
2018
2019 set(key, value) {
2020 const ks = Array.isArray(key) ? key : [key]; // $FlowOSSFixMe
2021
2022 let map = this._base;
2023 let next = map;
2024 ks.forEach(k => {
2025 next = map.get(k);
2026
2027 if (!next) {
2028 next = new Map();
2029 map.set(k, next);
2030 }
2031
2032 map = next;
2033 });
2034 next.set(LEAF, value);
2035 return this;
2036 }
2037
2038 delete(key) {
2039 const ks = Array.isArray(key) ? key : [key]; // $FlowOSSFixMe
2040
2041 let map = this._base;
2042 let next = map;
2043 ks.forEach(k => {
2044 next = map.get(k);
2045
2046 if (!next) {
2047 next = new Map();
2048 map.set(k, next);
2049 }
2050
2051 map = next;
2052 });
2053 next.delete(LEAF); // TODO We could cleanup empty maps
2054
2055 return this;
2056 }
2057
2058 entries() {
2059 const answer = [];
2060
2061 function recurse(level, prefix) {
2062 level.forEach((v, k) => {
2063 if (k === LEAF) {
2064 answer.push([prefix, v]);
2065 } else {
2066 recurse(v, prefix.concat(k));
2067 }
2068 });
2069 } // $FlowOSSFixMe
2070
2071
2072 recurse(this._base, []);
2073 return answer.values();
2074 }
2075
2076 toBuiltInMap() {
2077 return new Map(this.entries());
2078 }
2079
2080}
2081
2082var Recoil_ArrayKeyedMap = ArrayKeyedMap;
2083
2084function cacheWithReferenceEquality() {
2085 return new Recoil_ArrayKeyedMap();
2086}
2087
2088var Recoil_cacheWithReferenceEquality = cacheWithReferenceEquality;
2089
2090/**
2091 * Copyright (c) Facebook, Inc. and its affiliates.
2092 *
2093 * This source code is licensed under the MIT license found in the
2094 * LICENSE file in the root directory of this source tree.
2095 *
2096 * @emails oncall+recoil
2097 *
2098 * @format
2099 */
2100/**
2101 * The everySet() method tests whether all elements in the given Set pass the
2102 * test implemented by the provided function.
2103 */
2104
2105function everySet(set, callback, context) {
2106 const iterator = set.entries();
2107 let current = iterator.next();
2108
2109 while (!current.done) {
2110 const entry = current.value;
2111
2112 if (!callback.call(context, entry[1], entry[0], set)) {
2113 return false;
2114 }
2115
2116 current = iterator.next();
2117 }
2118
2119 return true;
2120}
2121
2122var Recoil_everySet = everySet;
2123
2124/**
2125 * Checks if two sets are equal
2126 */
2127
2128
2129function equalsSet(one, two) {
2130 if (one.size !== two.size) {
2131 return false;
2132 }
2133
2134 return Recoil_everySet(one, value => two.has(value));
2135}
2136
2137var Recoil_equalsSet = equalsSet;
2138
2139/**
2140 * Copyright (c) Facebook, Inc. and its affiliates.
2141 *
2142 * This source code is licensed under the MIT license found in the
2143 * LICENSE file in the root directory of this source tree.
2144 *
2145 * @emails oncall+recoil
2146 *
2147 * @format
2148 *
2149 * This is a stub for some integration into FB internal stuff
2150 */
2151function startPerfBlock(_id) {
2152 return () => null;
2153}
2154
2155var Recoil_PerformanceTimings = {
2156 startPerfBlock
2157};
2158
2159const emptySet$1 = Object.freeze(new Set());
2160
2161const {
2162 mapBySettingInMap: mapBySettingInMap$2,
2163 mapByUpdatingInMap: mapByUpdatingInMap$2,
2164 setByAddingToSet: setByAddingToSet$3,
2165 setByDeletingFromSet: setByDeletingFromSet$1
2166} = Recoil_CopyOnWrite;
2167
2168
2169
2170const {
2171 detectCircularDependencies: detectCircularDependencies$1,
2172 getNodeLoadable: getNodeLoadable$2,
2173 setNodeValue: setNodeValue$4
2174} = Recoil_FunctionalCore;
2175
2176const {
2177 loadableWithError: loadableWithError$1,
2178 loadableWithPromise: loadableWithPromise$1,
2179 loadableWithValue: loadableWithValue$1
2180} = Recoil_Loadable;
2181
2182const {
2183 DEFAULT_VALUE: DEFAULT_VALUE$3,
2184 RecoilValueNotReady: RecoilValueNotReady$2,
2185 registerNode: registerNode$1
2186} = Recoil_Node;
2187
2188const {
2189 startPerfBlock: startPerfBlock$1
2190} = Recoil_PerformanceTimings;
2191
2192const {
2193 isRecoilValue: isRecoilValue$2
2194} = Recoil_RecoilValue$1;
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204// flowlint-next-line unclear-type:off
2205const emptySet$2 = Object.freeze(new Set());
2206
2207function cacheKeyFromDepValues(depValues) {
2208 const answer = [];
2209
2210 for (const key of Array.from(depValues.keys()).sort()) {
2211 const loadable = Recoil_nullthrows(depValues.get(key));
2212 answer.push(key);
2213 answer.push(loadable.contents);
2214 }
2215
2216 return answer;
2217}
2218/* eslint-disable no-redeclare */
2219
2220
2221function selector(options) {
2222 const {
2223 key,
2224 get,
2225 cacheImplementation_UNSTABLE: cacheImplementation
2226 } = options;
2227 const set = options.set != null ? options.set : undefined; // flow
2228
2229 let cache = cacheImplementation !== null && cacheImplementation !== void 0 ? cacheImplementation : Recoil_cacheWithReferenceEquality();
2230
2231 function putIntoCache(store, cacheKey, loadable) {
2232 if (loadable.state !== 'loading') {
2233 // Synchronous result
2234 if (!options.dangerouslyAllowMutability === true) {
2235 Recoil_deepFreezeValue(loadable.contents);
2236 }
2237 } else {
2238 // Asynchronous result
2239 // When the promise resolves, we need to replace the loading state in the
2240 // cache and fire any external subscriptions to re-render with the new value.
2241 loadable.contents.then(result => {
2242 // If the value is now resolved, then update the cache with the new value
2243 if (!options.dangerouslyAllowMutability === true) {
2244 Recoil_deepFreezeValue(result);
2245 }
2246
2247 cache = cache.set(cacheKey, loadableWithValue$1(result)); // TODO Potential optimization: I think this is updating the cache
2248 // with a cacheKey of the dep when it wasn't ready yet. We could also
2249 // theoretically put the result in the cache for a cacheKey with the
2250 // dep resolved. If we had some way of figuring out what that cacheKey was..
2251 // Note that this optimization would change the user visible behavior slightly,
2252 // see the unit test "useRecoilState - selector catching promise 2".
2253 // If the user catches and handles pending async dependencies, then returns
2254 // a promise that resolves when they are available there is a question if
2255 // the result of that promise should be the value of the selector, or if
2256 // the selector should re-evaluate when the dependency is available.
2257 // If the promise returned and the pending dependency resolve at different
2258 // times, then the behaviour is better defined, as in the unit test,
2259 // "useRecoilState - selector catching promise and resolving asynchronously"
2260 // Fire subscriptions to re-render any subscribed components with the new value.
2261 // The store uses the CURRENT state, not the old state from which
2262 // this was called. That state likely doesn't have the subscriptions saved yet.
2263
2264 store.fireNodeSubscriptions(new Set([key]), 'now');
2265 return result;
2266 }).catch(error => {
2267 // TODO Figure out why we are catching promises here versus evaluateSelectorFunction
2268 // OH, I see why. Ok, work on this.
2269 if (Recoil_isPromise(error)) {
2270 return error;
2271 } // The async value was rejected with an error. Update the cache with
2272 // the error and fire subscriptions to re-render.
2273
2274
2275 if (!options.dangerouslyAllowMutability === true) {
2276 Recoil_deepFreezeValue(error);
2277 }
2278
2279 cache = cache.set(cacheKey, loadableWithError$1(error));
2280 store.fireNodeSubscriptions(new Set([key]), 'now');
2281 return error;
2282 });
2283 }
2284
2285 cache = cache.set(cacheKey, loadable);
2286 }
2287
2288 function getFromCache(store, state) {
2289 var _state$nodeDeps$get;
2290
2291 let newState = state; // First, get the current deps for this selector
2292
2293 const currentDeps = (_state$nodeDeps$get = state.nodeDeps.get(key)) !== null && _state$nodeDeps$get !== void 0 ? _state$nodeDeps$get : emptySet$2;
2294 const depValues = new Map(Array.from(currentDeps).sort().map(depKey => {
2295 const [nextState, loadable] = getNodeLoadable$2(store, newState, depKey);
2296 newState = nextState;
2297 return [depKey, loadable];
2298 })); // Always cache and evaluate a selector
2299 // It may provide a result even when not all deps are available.
2300
2301 const cacheKey = cacheKeyFromDepValues(depValues);
2302 const cached = cache.get(cacheKey);
2303
2304 if (cached != null) {
2305 return [newState, cached];
2306 } // Cache miss, compute the value
2307
2308
2309 const [nextState, loadable, newDepValues] = computeAndSubscribeSelector(store, newState);
2310 newState = nextState; // Save result in cache
2311
2312 const newCacheKey = cacheKeyFromDepValues(newDepValues);
2313 putIntoCache(store, newCacheKey, loadable);
2314 return [newState, loadable];
2315 }
2316
2317 function evaluateSelectorFunction(store, state) {
2318 const endPerfBlock = startPerfBlock$1(key);
2319 let newState = state;
2320 const depValues = new Map();
2321
2322 function getRecoilValue({
2323 key
2324 }) {
2325 let loadable;
2326 [newState, loadable] = getNodeLoadable$2(store, newState, key);
2327 depValues.set(key, loadable);
2328
2329 if (loadable.state === 'hasValue') {
2330 return loadable.contents;
2331 } else {
2332 throw loadable.contents; // Promise or error
2333 }
2334 }
2335
2336 try {
2337 // The big moment!
2338 const output = get({
2339 get: getRecoilValue
2340 });
2341 const result = isRecoilValue$2(output) ? getRecoilValue(output) : output; // TODO Allow user to also return Loadables for improved composability
2342
2343 const loadable = !Recoil_isPromise(result) ? ( // The selector returned a simple synchronous value, so let's use it!
2344 endPerfBlock(), loadableWithValue$1(result)) : // The user returned a promise for an asynchronous selector. This will
2345 // resolve to the proper value of the selector when available.
2346 loadableWithPromise$1(result.finally(endPerfBlock));
2347 return [newState, loadable, depValues];
2348 } catch (errorOrDepPromise) {
2349 const loadable = !Recoil_isPromise(errorOrDepPromise) ? ( // There was a synchronous error in the evaluation
2350 endPerfBlock(), loadableWithError$1(errorOrDepPromise)) : // If an asynchronous dependency was not ready, then return a promise that
2351 // will resolve when we finally do have a real value or error for the selector.
2352 loadableWithPromise$1(errorOrDepPromise.then(() => {
2353 // The dependency we were waiting on is now available.
2354 // So, let's try to evaluate the selector again and return that value.
2355 let loadable = loadableWithError$1(new Error('Internal Recoil Selector Error') // To make Flow happy
2356 ); // This is done asynchronously, so we need to make sure to save the state
2357
2358 store.replaceState(asyncState => {
2359 let newAsyncState;
2360 [newAsyncState, loadable] = getFromCache(store, asyncState);
2361 return newAsyncState;
2362 });
2363
2364 if (loadable.state === 'hasError') {
2365 throw loadable.contents;
2366 } // Either the re-try provided a value, which we will use, or it
2367 // got blocked again. In that case this is a promise and we'll try again.
2368
2369
2370 return loadable.contents;
2371 }).finally(endPerfBlock));
2372 return [newState, loadable, depValues];
2373 }
2374 }
2375
2376 function computeAndSubscribeSelector(store, state) {
2377 var _state$nodeDeps$get2;
2378
2379 // Call the selector get evaluation function to get the new value
2380 const [newStateFromEvaluate, loadable, newDepValues] = evaluateSelectorFunction(store, state);
2381 let newState = newStateFromEvaluate; // Update state with new upsteram dependencies
2382
2383 const oldDeps = (_state$nodeDeps$get2 = state.nodeDeps.get(key)) !== null && _state$nodeDeps$get2 !== void 0 ? _state$nodeDeps$get2 : emptySet$2;
2384 const newDeps = new Set(newDepValues.keys());
2385 newState = Recoil_equalsSet(oldDeps, newDeps) ? newState : { ...newState,
2386 nodeDeps: mapBySettingInMap$2(newState.nodeDeps, key, newDeps)
2387 }; // Update state with new downstream subscriptions
2388
2389 const addedDeps = Recoil_differenceSets(newDeps, oldDeps);
2390 const removedDeps = Recoil_differenceSets(oldDeps, newDeps);
2391
2392 for (const upstreamNode of addedDeps) {
2393 newState = { ...newState,
2394 nodeToNodeSubscriptions: mapByUpdatingInMap$2(newState.nodeToNodeSubscriptions, upstreamNode, subs => setByAddingToSet$3(subs !== null && subs !== void 0 ? subs : emptySet$2, key))
2395 };
2396 }
2397
2398 for (const upstreamNode of removedDeps) {
2399 newState = { ...newState,
2400 nodeToNodeSubscriptions: mapByUpdatingInMap$2(newState.nodeToNodeSubscriptions, upstreamNode, subs => setByDeletingFromSet$1(subs !== null && subs !== void 0 ? subs : emptySet$2, key))
2401 };
2402 }
2403
2404 {
2405 detectCircularDependencies$1(newState, [key]);
2406 }
2407
2408 return [newState, loadable, newDepValues];
2409 }
2410
2411 function myGet(store, state) {
2412 // TODO memoize a value if no deps have changed to avoid a cache lookup
2413 // Lookup the node value in the cache. If not there, then compute
2414 // the value and update the state with any changed node subscriptions.
2415 return getFromCache(store, state);
2416 }
2417
2418 if (set != null) {
2419 function mySet(store, state, newValue) {
2420 let newState = state;
2421 const writtenNodes = new Set();
2422
2423 function getRecoilValue({
2424 key
2425 }) {
2426 const [nextState, loadable] = getNodeLoadable$2(store, newState, key);
2427 newState = nextState;
2428
2429 if (loadable.state === 'hasValue') {
2430 return loadable.contents;
2431 } else if (loadable.state === 'loading') {
2432 throw new RecoilValueNotReady$2(key);
2433 } else {
2434 throw loadable.contents;
2435 }
2436 }
2437
2438 function setRecoilState(recoilState, valueOrUpdater) {
2439 const newValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict type S from being a function itself without losing support for opaque types
2440 // flowlint-next-line unclear-type:off
2441 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
2442 let written;
2443 [newState, written] = setNodeValue$4(store, newState, recoilState.key, newValue);
2444 written.forEach(atom => writtenNodes.add(atom));
2445 }
2446
2447 function resetRecoilState(recoilState) {
2448 setRecoilState(recoilState, DEFAULT_VALUE$3);
2449 }
2450
2451 set({
2452 set: setRecoilState,
2453 get: getRecoilValue,
2454 reset: resetRecoilState
2455 }, newValue);
2456 return [newState, writtenNodes];
2457 }
2458
2459 return registerNode$1({
2460 key,
2461 options,
2462 get: myGet,
2463 set: mySet
2464 });
2465 } else {
2466 return registerNode$1({
2467 key,
2468 options,
2469 get: myGet
2470 });
2471 }
2472}
2473/* eslint-enable no-redeclare */
2474
2475
2476var Recoil_selector_OLD = selector;
2477
2478const selector$1 = Recoil_selector_OLD;
2479var Recoil_selector = selector$1;
2480
2481// @fb-only: import type {ScopeRules} from './Recoil_ScopedAtom';
2482const {
2483 loadableWithValue: loadableWithValue$2
2484} = Recoil_Loadable;
2485
2486const {
2487 DEFAULT_VALUE: DEFAULT_VALUE$4,
2488 DefaultValue: DefaultValue$1,
2489 registerNode: registerNode$2
2490} = Recoil_Node;
2491
2492const {
2493 isRecoilValue: isRecoilValue$3
2494} = Recoil_RecoilValue$1;
2495
2496const {
2497 mapByDeletingFromMap: mapByDeletingFromMap$2,
2498 mapBySettingInMap: mapBySettingInMap$3,
2499 setByAddingToSet: setByAddingToSet$4
2500} = Recoil_CopyOnWrite;
2501
2502
2503
2504
2505
2506
2507
2508 // @fb-only: const {scopedAtom} = require('./Recoil_ScopedAtom');
2509
2510
2511 // It would be nice if this didn't have to be defined at the Recoil level, but I don't want to make
2512// the api cumbersome. One way to do this would be to have a selector mark the atom as persisted.
2513// Note that this should also allow for special URL handling. (Although the persistence observer could
2514// have this as a separate configuration.)
2515
2516
2517function baseAtom(options) {
2518 const {
2519 key,
2520 persistence_UNSTABLE: persistence
2521 } = options;
2522 return registerNode$2({
2523 key,
2524 options,
2525 get: (_store, state) => {
2526 if (state.atomValues.has(key)) {
2527 // atom value is stored in state
2528 return [state, Recoil_nullthrows(state.atomValues.get(key))];
2529 } else if (state.nonvalidatedAtoms.has(key)) {
2530 if (persistence == null) {
2531 Recoil_expectationViolation(`Tried to restore a persisted value for atom ${key} but it has no persistence settings.`);
2532 return [state, loadableWithValue$2(options.default)];
2533 }
2534
2535 const nonvalidatedValue = state.nonvalidatedAtoms.get(key);
2536 const validatedValue = persistence.validator(nonvalidatedValue, DEFAULT_VALUE$4);
2537 return validatedValue instanceof DefaultValue$1 ? [{ ...state,
2538 nonvalidatedAtoms: mapByDeletingFromMap$2(state.nonvalidatedAtoms, key)
2539 }, loadableWithValue$2(options.default)] : [{ ...state,
2540 atomValues: mapBySettingInMap$3(state.atomValues, key, loadableWithValue$2(validatedValue)),
2541 nonvalidatedAtoms: mapByDeletingFromMap$2(state.nonvalidatedAtoms, key)
2542 }, loadableWithValue$2(validatedValue)];
2543 } else {
2544 return [state, loadableWithValue$2(options.default)];
2545 }
2546 },
2547 set: (_store, state, newValue) => {
2548 if (options.dangerouslyAllowMutability !== true) {
2549 Recoil_deepFreezeValue(newValue);
2550 }
2551
2552 return [{ ...state,
2553 dirtyAtoms: setByAddingToSet$4(state.dirtyAtoms, key),
2554 atomValues: newValue instanceof DefaultValue$1 ? mapByDeletingFromMap$2(state.atomValues, key) : mapBySettingInMap$3(state.atomValues, key, loadableWithValue$2(newValue)),
2555 nonvalidatedAtoms: mapByDeletingFromMap$2(state.nonvalidatedAtoms, key)
2556 }, new Set([key])];
2557 }
2558 });
2559} // prettier-ignore
2560
2561
2562function atom(options) {
2563 const {
2564 default: optionsDefault,
2565 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
2566 ...restOptions
2567 } = options;
2568
2569 if (isRecoilValue$3(optionsDefault) || Recoil_isPromise(optionsDefault)) {
2570 return atomWithFallback({ ...restOptions,
2571 default: optionsDefault // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
2572
2573 }); // @fb-only: } else if (scopeRules_APPEND_ONLY_READ_THE_DOCS) {
2574 // @fb-only: return scopedAtom<T>({
2575 // @fb-only: ...restOptions,
2576 // @fb-only: default: optionsDefault,
2577 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
2578 // @fb-only: });
2579 } else {
2580 return baseAtom({ ...restOptions,
2581 default: optionsDefault
2582 });
2583 }
2584}
2585
2586function atomWithFallback(options) {
2587 const base = atom({ ...options,
2588 default: DEFAULT_VALUE$4,
2589 persistence_UNSTABLE: options.persistence_UNSTABLE === undefined ? undefined : { ...options.persistence_UNSTABLE,
2590 validator: storedValue => storedValue instanceof DefaultValue$1 ? storedValue : Recoil_nullthrows(options.persistence_UNSTABLE).validator(storedValue, DEFAULT_VALUE$4)
2591 }
2592 });
2593 return Recoil_selector({
2594 key: `${options.key}__withFallback`,
2595 get: ({
2596 get
2597 }) => {
2598 const baseValue = get(base);
2599 return baseValue instanceof DefaultValue$1 ? options.default : baseValue;
2600 },
2601 set: ({
2602 set
2603 }, newValue) => set(base, newValue),
2604 dangerouslyAllowMutability: options.dangerouslyAllowMutability
2605 });
2606}
2607
2608var Recoil_atom = atom;
2609
2610/**
2611 * Copyright (c) Facebook, Inc. and its affiliates.
2612 *
2613 * This source code is licensed under the MIT license found in the
2614 * LICENSE file in the root directory of this source tree.
2615 *
2616 * @emails oncall+recoil
2617 *
2618 * @format
2619 */
2620
2621var Recoil_ParameterizedAtomTaggedValue_DEPRECATED = /*#__PURE__*/Object.freeze({
2622 __proto__: null
2623});
2624
2625const TIME_WARNING_THRESHOLD_MS = 15;
2626
2627function stringify(x, opt, key) {
2628 // A optimization to avoid the more expensive JSON.stringify() for simple strings
2629 // This may lose protection for u2028 and u2029, though.
2630 if (typeof x === 'string' && !x.includes('"') && !x.includes('\\')) {
2631 return `"${x}"`;
2632 } // Handle primitive types
2633
2634
2635 switch (typeof x) {
2636 case 'undefined':
2637 return '';
2638 // JSON.stringify(undefined) returns undefined, but we always want to return a string
2639
2640 case 'boolean':
2641 return x ? 'true' : 'false';
2642
2643 case 'number':
2644 case 'symbol':
2645 // case 'bigint': // BigInt is not supported in www
2646 return String(x);
2647
2648 case 'string':
2649 // Add surrounding quotes and escape internal quotes
2650 return JSON.stringify(x);
2651
2652 case 'function':
2653 if ((opt === null || opt === void 0 ? void 0 : opt.allowFunctions) !== true) {
2654 throw new Error('Attempt to serialize function in a Recoil cache key');
2655 }
2656
2657 return `__FUNCTION(${x.name})__`;
2658 }
2659
2660 if (x === null) {
2661 return 'null';
2662 } // Fallback case for unknown types
2663
2664
2665 if (typeof x !== 'object') {
2666 var _JSON$stringify;
2667
2668 return (_JSON$stringify = JSON.stringify(x)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : '';
2669 } // Deal with all promises as equivalent for now.
2670
2671
2672 if (Recoil_isPromise(x)) {
2673 return '__PROMISE__';
2674 } // Arrays handle recursive stringification
2675
2676
2677 if (Array.isArray(x)) {
2678 return `[${x.map((v, i) => stringify(v, opt, i.toString()))}]`;
2679 } // If an object defines a toJSON() method, then use that to override the
2680 // serialization. This matches the behavior of JSON.stringify().
2681 // Pass the key for compatibility.
2682 // Immutable.js collections define this method to allow us to serialize them.
2683
2684
2685 if (typeof x.toJSON === 'function') {
2686 // flowlint-next-line unclear-type: off
2687 return stringify(x.toJSON(key), opt, key);
2688 } // For built-in Maps, sort the keys in a stable order instead of the
2689 // default insertion order. Support non-string keys.
2690
2691
2692 if (x instanceof Map) {
2693 return stringify( // TODO Object.fromEntries(x) isn't supported in Babel yet (7/17/19)
2694 Array.from(x).reduce((obj, [k, v]) => ({ ...obj,
2695 // Stringify will escape any nested quotes
2696 [typeof k === 'string' ? k : stringify(k, opt)]: v
2697 }), {}), opt, key);
2698 } // For built-in Sets, sort the keys in a stable order instead of the
2699 // default insertion order.
2700
2701
2702 if (x instanceof Set) {
2703 return stringify(Array.from(x).sort((a, b) => stringify(a, opt).localeCompare(stringify(b, opt))), opt, key);
2704 } // Anything else that is iterable serialize as an Array.
2705
2706
2707 if (x[Symbol.iterator] != null && typeof x[Symbol.iterator] === 'function') {
2708 // flowlint-next-line unclear-type: off
2709 return stringify(Array.from(x), opt, key);
2710 } // For all other Objects, sort the keys in a stable order.
2711
2712
2713 return `{${Object.keys(x).filter(key => x[key] !== undefined).sort() // stringify the key to add quotes and escape any nested slashes or quotes.
2714 .map(key => `${stringify(key, opt)}:${stringify(x[key], opt, key)}`).join(',')}}`;
2715} // Utility similar to JSON.stringify() except:
2716// * Serialize built-in Sets as an Array
2717// * Serialize built-in Maps as an Object. Supports non-string keys.
2718// * Serialize other iterables as arrays
2719// * Sort the keys of Objects and Maps to have a stable order based on string conversion.
2720// This overrides their default insertion order.
2721// * Still uses toJSON() of any object to override serialization
2722// * Support Symbols (though don't guarantee uniqueness)
2723// * We could support BigInt, but Flow doesn't seem to like it.
2724// See Recoil_stableStringify-test.js for examples
2725
2726
2727function stableStringify(x, opt = {
2728 allowFunctions: false
2729}) {
2730 {
2731 if (typeof window !== 'undefined') {
2732 const startTime = window.performance ? window.performance.now() : 0;
2733 const str = stringify(x, opt);
2734 const endTime = window.performance ? window.performance.now() : 0;
2735
2736 if (endTime - startTime > TIME_WARNING_THRESHOLD_MS) {
2737 /* eslint-disable fb-www/no-console */
2738 console.groupCollapsed(`Recoil: Spent ${endTime - startTime}ms computing a cache key`);
2739 console.warn(x, str);
2740 console.groupEnd();
2741 /* eslint-enable fb-www/no-console */
2742 }
2743
2744 return str;
2745 }
2746 }
2747
2748 return stringify(x, opt);
2749}
2750
2751var Recoil_stableStringify = stableStringify;
2752
2753// If we do profile and find the key equality check is expensive,
2754// we could always try to optimize.. Something that comes to mind is having
2755// each check assign an incrementing index to each reference that maps to the
2756// value equivalency. Then, if an object already has an index, the comparison
2757// check/lookup would be trivial and the string serialization would only need
2758// to be done once per object instance. Just a thought..
2759// Cache implementation to use value equality for keys instead of the default
2760// reference equality. This allows different instances of dependency values to
2761// be used. Normally this is not needed, as dependent atoms/selectors will
2762// themselves be cached and always return the same instance. However, if
2763// different params or upstream values for those dependencies could produce
2764// equivalent values or they have a custom cache implementation, then this
2765// implementation may be needed. The downside with this approach is that it
2766// takes longer to compute the value equivalence vs simple reference equality.
2767
2768
2769function cacheWithValueEquality() {
2770 const map = new Map();
2771 const cache = {
2772 get: key => map.get(Recoil_stableStringify(key)),
2773 set: (key, value) => {
2774 map.set(Recoil_stableStringify(key), value);
2775 return cache;
2776 },
2777 map // For debugging
2778
2779 };
2780 return cache;
2781}
2782
2783var Recoil_cacheWithValueEquality = cacheWithValueEquality;
2784
2785// Keep in mind the parameter needs to be serializable as a cahche key
2786// using Recoil_stableStringify
2787
2788
2789// Add a unique index to each selector in case the cache implementation allows
2790// duplicate keys based on equivalent stringified parameters
2791let nextIndex = 0;
2792/* eslint-disable no-redeclare */
2793
2794// Return a function that returns members of a family of selectors of the same type
2795// E.g.,
2796//
2797// const s = selectorFamily(...);
2798// s({a: 1}) => a selector
2799// s({a: 2}) => a different selector
2800//
2801// By default, the selectors are distinguished by distinct values of the
2802// parameter based on value equality, not reference equality. This allows using
2803// object literals or other equivalent objects at callsites to not create
2804// duplicate cache entries. This behavior may be overridden with the
2805// cacheImplementationForParams option.
2806function selectorFamily(options) {
2807 var _options$cacheImpleme, _options$cacheImpleme2;
2808
2809 let selectorCache = (_options$cacheImpleme = (_options$cacheImpleme2 = options.cacheImplementationForParams_UNSTABLE) === null || _options$cacheImpleme2 === void 0 ? void 0 : _options$cacheImpleme2.call(options)) !== null && _options$cacheImpleme !== void 0 ? _options$cacheImpleme : Recoil_cacheWithValueEquality();
2810 return params => {
2811 var _stableStringify, _options$cacheImpleme3;
2812
2813 const cachedSelector = selectorCache.get(params);
2814
2815 if (cachedSelector != null) {
2816 return cachedSelector;
2817 }
2818
2819 const myKey = `${options.key}__selectorFamily/${(_stableStringify = Recoil_stableStringify(params, {
2820 // It is possible to use functions in parameters if the user uses
2821 // a cache with reference equality thanks to the incrementing index.
2822 allowFunctions: true
2823 })) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}/${nextIndex++}`; // Append index in case values serialize to the same key string
2824
2825 const myGet = callbacks => options.get(params)(callbacks);
2826
2827 const myCacheImplementation = (_options$cacheImpleme3 = options.cacheImplementation_UNSTABLE) === null || _options$cacheImpleme3 === void 0 ? void 0 : _options$cacheImpleme3.call(options);
2828 let newSelector;
2829
2830 if (options.set != null) {
2831 const set = options.set;
2832
2833 const mySet = (callbacks, newValue) => set(params)(callbacks, newValue);
2834
2835 newSelector = Recoil_selector({
2836 key: myKey,
2837 get: myGet,
2838 set: mySet,
2839 cacheImplementation_UNSTABLE: myCacheImplementation,
2840 dangerouslyAllowMutability: options.dangerouslyAllowMutability
2841 });
2842 } else {
2843 newSelector = Recoil_selector({
2844 key: myKey,
2845 get: myGet,
2846 cacheImplementation_UNSTABLE: myCacheImplementation,
2847 dangerouslyAllowMutability: options.dangerouslyAllowMutability
2848 });
2849 }
2850
2851 selectorCache = selectorCache.set(params, newSelector);
2852 return newSelector;
2853 };
2854}
2855/* eslint-enable no-redeclare */
2856
2857
2858var Recoil_selectorFamily = selectorFamily;
2859
2860// @fb-only: import type {ScopeRules} from './Recoil_ScopedAtom';
2861
2862
2863
2864
2865const {
2866 DEFAULT_VALUE: DEFAULT_VALUE$5,
2867 DefaultValue: DefaultValue$2
2868} = Recoil_Node;
2869
2870
2871
2872
2873
2874 // @fb-only: const {parameterizedScopedAtomLegacy} = require('./Recoil_ScopedAtom');
2875
2876
2877
2878
2879function isSuperset(setA, setB) {
2880 return Recoil_everySet(setB, b => setA.has(b));
2881}
2882
2883const pick = (object, chosenKeys) => Array.from(chosenKeys).reduce((obj, key) => ({ ...obj,
2884 [key]: object[key]
2885}), {});
2886
2887function getParameterizedValue_DEPRECATED(baseValue, parameter) {
2888 // Allow simple atoms to be upgraded to atomFamilies
2889 if (!(baseValue instanceof Recoil_ParameterizedAtomTaggedValue_DEPRECATED)) {
2890 return baseValue;
2891 } // Legacy ParameterizedAtomTaggedValue only supported object type parameters
2892
2893
2894 if (typeof parameter !== 'object' || parameter == null || Array.isArray(parameter)) {
2895 return DEFAULT_VALUE$5;
2896 }
2897
2898 const entries = baseValue.value;
2899 const parameterKeys = new Set(Object.keys(parameter));
2900
2901 for (const [entryParameterKeys, entryMap] of entries) {
2902 if (isSuperset(parameterKeys, entryParameterKeys)) {
2903 const contextOrSubcontext = parameterKeys.size === entryParameterKeys.size // if true they are equal
2904 ? parameter : pick(parameter, entryParameterKeys);
2905 const value = entryMap.get(Recoil_stableStringify(contextOrSubcontext));
2906
2907 if (value !== undefined) {
2908 return value;
2909 }
2910 }
2911 }
2912
2913 return DEFAULT_VALUE$5;
2914}
2915
2916function mapPersistenceSettings_DEPRECATED(settings) {
2917 if (settings == null) {
2918 return undefined;
2919 }
2920
2921 const { ...passthrough
2922 } = settings;
2923 return { ...passthrough,
2924 validator: storedValue => {
2925 if (storedValue instanceof Recoil_ParameterizedAtomTaggedValue_DEPRECATED) {
2926 return new Recoil_ParameterizedAtomTaggedValue_DEPRECATED(storedValue.value.filter(([keys, map]) => keys instanceof Set && map instanceof Map).map(([keys, map]) => [keys, Array.from(map.entries()).reduce((acc, [k, v]) => {
2927 const validatedValue = passthrough.validator(v, DEFAULT_VALUE$5);
2928
2929 if (validatedValue instanceof DefaultValue$2) {
2930 return acc;
2931 }
2932
2933 acc.set(k, validatedValue);
2934 return acc;
2935 }, new Map())]));
2936 } else {
2937 return passthrough.validator(storedValue, DEFAULT_VALUE$5);
2938 }
2939 }
2940 };
2941} // Process scopeRules to handle any entries which are functions taking parameters
2942/*
2943A function which returns an atom based on the input parameter.
2944
2945Each unique parameter returns a unique atom. E.g.,
2946
2947 const f = atomFamily(...);
2948 f({a: 1}) => an atom
2949 f({a: 2}) => a different atom
2950
2951This allows components to persist local, private state using atoms. Each
2952instance of the component may have a different key, which it uses as the
2953parameter for a family of atoms; in this way, each component will have
2954its own atom not shared by other instances. These state keys may be composed
2955into children's state keys as well.
2956*/
2957
2958
2959function atomFamily(options) {
2960 let atomCache = Recoil_cacheWithValueEquality(); // An atom to represent any legacy atoms that we can upgrade to an atomFamily
2961
2962 const legacyAtomOptions = {
2963 key: options.key,
2964 // Legacy atoms just used the plain key directly
2965 default: DEFAULT_VALUE$5,
2966 // TODO Drop support for ParameterizedAtomTaggedValue_DEPRECATED June 2020
2967 persistence_UNSTABLE: mapPersistenceSettings_DEPRECATED(options.persistence_UNSTABLE)
2968 };
2969 let legacyAtom; // prettier-ignore
2970 // @fb-only: if (
2971 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS
2972 // @fb-only: ) {
2973 // @fb-only: legacyAtom = parameterizedScopedAtomLegacy<
2974 // @fb-only: StoredBaseValue_DEPRECATED<T> | DefaultValue,
2975 // @fb-only: P,
2976 // @fb-only: >({
2977 // @fb-only: ...legacyAtomOptions,
2978 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS:
2979 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
2980 // @fb-only: });
2981 // @fb-only: } else {
2982
2983 legacyAtom = Recoil_atom(legacyAtomOptions); // @fb-only: }
2984 // Selector to calculate the default value based on any persisted legacy atoms
2985 // that were upgraded to a atomFamily
2986
2987 const atomFamilyDefault = Recoil_selectorFamily({
2988 key: `${options.key}__atomFamily/Default`,
2989 get: param => ({
2990 get
2991 }) => {
2992 const legacyValue = get(typeof legacyAtom === 'function' ? legacyAtom(param) : legacyAtom);
2993
2994 if (!(legacyValue instanceof DefaultValue$2)) {
2995 // Atom was upgraded from a non-parameterized atom
2996 // or a legacy ParameterizedAtomTaggedValue
2997 // TODO Drop support for ParameterizedAtomTaggedValue_DEPRECATED June 2020
2998 const upgradedValue = getParameterizedValue_DEPRECATED(legacyValue, param);
2999
3000 if (!(upgradedValue instanceof DefaultValue$2)) {
3001 return upgradedValue;
3002 }
3003 } // There's no legacy atom value, so use the user-specified default
3004
3005
3006 return typeof options.default === 'function' ? // The default was parameterized
3007 // Flow doesn't know that T isn't a function, so we need to case to any
3008 options.default(param) // flowlint-line unclear-type:off
3009 : // Default may be a static value, promise, or RecoilValue
3010 options.default;
3011 },
3012 dangerouslyAllowMutability: options.dangerouslyAllowMutability
3013 }); // Simple atomFamily implementation to cache individual atoms based
3014 // on the parameter value equality.
3015
3016 return params => {
3017 var _stableStringify;
3018
3019 const cachedAtom = atomCache.get(params);
3020
3021 if (cachedAtom != null) {
3022 return cachedAtom;
3023 }
3024
3025 const newAtom = Recoil_atom({
3026 key: `${options.key}__${(_stableStringify = Recoil_stableStringify(params)) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}`,
3027 default: atomFamilyDefault(params),
3028 // prettier-ignore
3029 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS: mapScopeRules(
3030 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
3031 // @fb-only: params,
3032 // @fb-only: ),
3033 persistence_UNSTABLE: options.persistence_UNSTABLE,
3034 dangerouslyAllowMutability: options.dangerouslyAllowMutability
3035 });
3036 atomCache = atomCache.set(params, newAtom);
3037 return newAtom;
3038 };
3039}
3040
3041var Recoil_atomFamily = atomFamily;
3042
3043// flowlint-next-line unclear-type:off
3044
3045
3046const constantSelector = Recoil_selectorFamily({
3047 key: '__constant',
3048 get: constant => () => constant,
3049 cacheImplementationForParams_UNSTABLE: Recoil_cacheWithReferenceEquality
3050}); // Function that returns a selector which always produces the
3051// same constant value. It may be called multiple times with the
3052// same value, based on reference equality, and will provide the
3053// same selector.
3054
3055function constSelector(constant) {
3056 return constantSelector(constant);
3057}
3058
3059var Recoil_constSelector = constSelector;
3060
3061// flowlint-next-line unclear-type:off
3062
3063
3064const throwingSelector = Recoil_selectorFamily({
3065 key: '__error',
3066 get: message => () => {
3067 throw new Error(message);
3068 },
3069 cacheImplementationForParams_UNSTABLE: Recoil_cacheWithReferenceEquality
3070}); // Function that returns a selector which always throws an error
3071// with the provided message.
3072
3073function errorSelector(message) {
3074 return throwingSelector(message);
3075}
3076
3077var Recoil_errorSelector = errorSelector;
3078
3079/**
3080 * Copyright (c) Facebook, Inc. and its affiliates.
3081 *
3082 * This source code is licensed under the MIT license found in the
3083 * LICENSE file in the root directory of this source tree.
3084 *
3085 * Wraps another recoil value and prevents writing to it.
3086 *
3087 * @emails oncall+recoil
3088 *
3089 * @format
3090 */
3091
3092function readOnlySelector(atom) {
3093 // flowlint-next-line unclear-type: off
3094 return atom;
3095}
3096
3097var Recoil_readOnlySelector = readOnlySelector;
3098
3099const {
3100 loadableWithError: loadableWithError$2,
3101 loadableWithPromise: loadableWithPromise$2,
3102 loadableWithValue: loadableWithValue$3
3103} = Recoil_Loadable;
3104
3105
3106
3107 /////////////////
3108// TRUTH TABLE
3109/////////////////
3110// Dependencies waitForNone waitForAny waitForAll
3111// [loading, loading] [Promise, Promise] Promise Promise
3112// [value, loading] [value, Promise] [value, Promise] Promise
3113// [value, value] [value, value] [value, value] [value, value]
3114//
3115// [error, loading] [Error, Promise] Promise Error
3116// [error, error] [Error, Error] Error Error
3117// [value, error] [value, Error] [value, Error] Error
3118// Issue parallel requests for all dependencies and return the current
3119// status if they have results, have some error, or are still pending.
3120
3121
3122function concurrentRequests(getRecoilValue, deps) {
3123 const results = Array(deps.length).fill(undefined);
3124 const exceptions = Array(deps.length).fill(undefined);
3125
3126 for (const [i, dep] of deps.entries()) {
3127 try {
3128 results[i] = getRecoilValue(dep);
3129 } catch (e) {
3130 // exceptions can either be Promises of pending results or real errors
3131 exceptions[i] = e;
3132 }
3133 }
3134
3135 return [results, exceptions];
3136}
3137
3138function isError(exp) {
3139 return exp != null && !Recoil_isPromise(exp);
3140}
3141
3142function unwrapDependencies(dependencies) {
3143 return Array.isArray(dependencies) ? dependencies : Object.getOwnPropertyNames(dependencies).map(key => dependencies[key]);
3144}
3145
3146function wrapResults(dependencies, results) {
3147 return Array.isArray(dependencies) ? results : // Object.getOwnPropertyNames() has consistent key ordering with ES6
3148 Object.getOwnPropertyNames(dependencies).reduce((out, key, idx) => ({ ...out,
3149 [key]: results[idx]
3150 }), {});
3151}
3152
3153function wrapLoadables(dependencies, results, exceptions) {
3154 const output = exceptions.map((exception, idx) => exception == null ? loadableWithValue$3(results[idx]) : Recoil_isPromise(exception) ? loadableWithPromise$2(exception) : loadableWithError$2(exception));
3155 return wrapResults(dependencies, output);
3156} // Selector that requests all dependencies in parallel and immediately returns
3157// current results without waiting.
3158
3159
3160const waitForNone = Recoil_selectorFamily({
3161 key: '__waitForNone',
3162 get: dependencies => ({
3163 get
3164 }) => {
3165 // Issue requests for all dependencies in parallel.
3166 const deps = unwrapDependencies(dependencies);
3167 const [results, exceptions] = concurrentRequests(get, deps); // Always return the current status of the results; never block.
3168
3169 return wrapLoadables(dependencies, results, exceptions);
3170 }
3171}); // Selector that requests all dependencies in parallel and waits for at least
3172// one to be available before returning results. It will only error if all
3173// dependencies have errors.
3174
3175const waitForAny = Recoil_selectorFamily({
3176 key: '__waitForAny',
3177 get: dependencies => ({
3178 get
3179 }) => {
3180 // Issue requests for all dependencies in parallel.
3181 // Exceptions can either be Promises of pending results or real errors
3182 const deps = unwrapDependencies(dependencies);
3183 const [results, exceptions] = concurrentRequests(get, deps); // If any results are available, return the current status
3184
3185 if (exceptions.some(exp => exp == null)) {
3186 return wrapLoadables(dependencies, results, exceptions);
3187 } // Since we are waiting for any results, only throw an error if all
3188 // dependencies have an error. Then, throw the first one.
3189
3190
3191 if (exceptions.every(isError)) {
3192 throw exceptions.find(isError);
3193 }
3194
3195 {
3196 throw new Promise((resolve, reject) => {
3197 for (const [i, exp] of exceptions.entries()) {
3198 if (Recoil_isPromise(exp)) {
3199 exp.then(result => {
3200 results[i] = result;
3201 exceptions[i] = null;
3202 resolve(wrapLoadables(dependencies, results, exceptions));
3203 }).catch(error => {
3204 exceptions[i] = error;
3205
3206 if (exceptions.every(isError)) {
3207 reject(exceptions[0]);
3208 }
3209 });
3210 }
3211 }
3212 });
3213 }
3214 }
3215}); // Selector that requests all dependencies in parallel and waits for all to be
3216// available before returning a value. It will error if any dependencies error.
3217
3218const waitForAll = Recoil_selectorFamily({
3219 key: '__waitForAll',
3220 get: dependencies => ({
3221 get
3222 }) => {
3223 // Issue requests for all dependencies in parallel.
3224 // Exceptions can either be Promises of pending results or real errors
3225 const deps = unwrapDependencies(dependencies);
3226 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
3227
3228 if (exceptions.every(exp => exp == null)) {
3229 return wrapResults(dependencies, results);
3230 } // If we have any errors, throw the first error
3231
3232
3233 const error = exceptions.find(isError);
3234
3235 if (error != null) {
3236 throw error;
3237 }
3238
3239 {
3240 throw Promise.all(exceptions).then(results => wrapResults(dependencies, results));
3241 }
3242 }
3243});
3244const noWait = Recoil_selectorFamily({
3245 key: '__noWait',
3246 get: dependency => ({
3247 get
3248 }) => {
3249 try {
3250 return loadableWithValue$3(get(dependency));
3251 } catch (exception) {
3252 return Recoil_isPromise(exception) ? loadableWithPromise$2(exception) : loadableWithError$2(exception);
3253 }
3254 }
3255});
3256var Recoil_WaitFor = {
3257 waitForNone,
3258 waitForAny,
3259 waitForAll,
3260 noWait
3261};
3262
3263const {
3264 DefaultValue: DefaultValue$3
3265} = Recoil_Node;
3266
3267const {
3268 RecoilRoot: RecoilRoot$1
3269} = Recoil_RecoilRoot_react;
3270
3271const {
3272 isRecoilValue: isRecoilValue$4
3273} = Recoil_RecoilValue$1;
3274
3275const {
3276 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
3277 useRecoilCallback: useRecoilCallback$1,
3278 useRecoilSnapshot: useRecoilSnapshot$1,
3279 useRecoilState: useRecoilState$1,
3280 useRecoilStateLoadable: useRecoilStateLoadable$1,
3281 useRecoilTransactionObserver: useRecoilTransactionObserver$1,
3282 useRecoilValue: useRecoilValue$1,
3283 useRecoilValueLoadable: useRecoilValueLoadable$1,
3284 useResetRecoilState: useResetRecoilState$1,
3285 useSetRecoilState: useSetRecoilState$1,
3286 useSetUnvalidatedAtomValues: useSetUnvalidatedAtomValues$1,
3287 useTransactionObservation_DEPRECATED: useTransactionObservation_DEPRECATED$1
3288} = Recoil_Hooks;
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304const {
3305 noWait: noWait$1,
3306 waitForAll: waitForAll$1,
3307 waitForAny: waitForAny$1,
3308 waitForNone: waitForNone$1
3309} = Recoil_WaitFor;
3310
3311var Recoil_index = {
3312 // Types
3313 DefaultValue: DefaultValue$3,
3314 // Components
3315 RecoilRoot: RecoilRoot$1,
3316 // RecoilValues
3317 atom: Recoil_atom,
3318 selector: Recoil_selector,
3319 // Convenience RecoilValues
3320 atomFamily: Recoil_atomFamily,
3321 selectorFamily: Recoil_selectorFamily,
3322 constSelector: Recoil_constSelector,
3323 errorSelector: Recoil_errorSelector,
3324 readOnlySelector: Recoil_readOnlySelector,
3325 // Hooks that accept RecoilValues
3326 useRecoilValue: useRecoilValue$1,
3327 useRecoilValueLoadable: useRecoilValueLoadable$1,
3328 useRecoilState: useRecoilState$1,
3329 useRecoilStateLoadable: useRecoilStateLoadable$1,
3330 useSetRecoilState: useSetRecoilState$1,
3331 useResetRecoilState: useResetRecoilState$1,
3332 // Hooks for asynchronous Recoil
3333 useRecoilCallback: useRecoilCallback$1,
3334 // Hooks for Snapshots
3335 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
3336 useRecoilSnapshot: useRecoilSnapshot$1,
3337 useRecoilTransactionObserver_UNSTABLE: useRecoilTransactionObserver$1,
3338 useTransactionObservation_UNSTABLE: useTransactionObservation_DEPRECATED$1,
3339 useSetUnvalidatedAtomValues_UNSTABLE: useSetUnvalidatedAtomValues$1,
3340 // Concurrency Helpers
3341 noWait: noWait$1,
3342 waitForNone: waitForNone$1,
3343 waitForAny: waitForAny$1,
3344 waitForAll: waitForAll$1,
3345 // Other functions
3346 isRecoilValue: isRecoilValue$4
3347};
3348var Recoil_index_1 = Recoil_index.DefaultValue;
3349var Recoil_index_2 = Recoil_index.RecoilRoot;
3350var Recoil_index_3 = Recoil_index.atom;
3351var Recoil_index_4 = Recoil_index.selector;
3352var Recoil_index_5 = Recoil_index.atomFamily;
3353var Recoil_index_6 = Recoil_index.selectorFamily;
3354var Recoil_index_7 = Recoil_index.constSelector;
3355var Recoil_index_8 = Recoil_index.errorSelector;
3356var Recoil_index_9 = Recoil_index.readOnlySelector;
3357var Recoil_index_10 = Recoil_index.useRecoilValue;
3358var Recoil_index_11 = Recoil_index.useRecoilValueLoadable;
3359var Recoil_index_12 = Recoil_index.useRecoilState;
3360var Recoil_index_13 = Recoil_index.useRecoilStateLoadable;
3361var Recoil_index_14 = Recoil_index.useSetRecoilState;
3362var Recoil_index_15 = Recoil_index.useResetRecoilState;
3363var Recoil_index_16 = Recoil_index.useRecoilCallback;
3364var Recoil_index_17 = Recoil_index.useGotoRecoilSnapshot;
3365var Recoil_index_18 = Recoil_index.useRecoilSnapshot;
3366var Recoil_index_19 = Recoil_index.useRecoilTransactionObserver_UNSTABLE;
3367var Recoil_index_20 = Recoil_index.useTransactionObservation_UNSTABLE;
3368var Recoil_index_21 = Recoil_index.useSetUnvalidatedAtomValues_UNSTABLE;
3369var Recoil_index_22 = Recoil_index.noWait;
3370var Recoil_index_23 = Recoil_index.waitForNone;
3371var Recoil_index_24 = Recoil_index.waitForAny;
3372var Recoil_index_25 = Recoil_index.waitForAll;
3373var Recoil_index_26 = Recoil_index.isRecoilValue;
3374
3375exports.DefaultValue = Recoil_index_1;
3376exports.RecoilRoot = Recoil_index_2;
3377exports.atom = Recoil_index_3;
3378exports.atomFamily = Recoil_index_5;
3379exports.constSelector = Recoil_index_7;
3380exports.default = Recoil_index;
3381exports.errorSelector = Recoil_index_8;
3382exports.isRecoilValue = Recoil_index_26;
3383exports.noWait = Recoil_index_22;
3384exports.readOnlySelector = Recoil_index_9;
3385exports.selector = Recoil_index_4;
3386exports.selectorFamily = Recoil_index_6;
3387exports.useGotoRecoilSnapshot = Recoil_index_17;
3388exports.useRecoilCallback = Recoil_index_16;
3389exports.useRecoilSnapshot = Recoil_index_18;
3390exports.useRecoilState = Recoil_index_12;
3391exports.useRecoilStateLoadable = Recoil_index_13;
3392exports.useRecoilTransactionObserver_UNSTABLE = Recoil_index_19;
3393exports.useRecoilValue = Recoil_index_10;
3394exports.useRecoilValueLoadable = Recoil_index_11;
3395exports.useResetRecoilState = Recoil_index_15;
3396exports.useSetRecoilState = Recoil_index_14;
3397exports.useSetUnvalidatedAtomValues_UNSTABLE = Recoil_index_21;
3398exports.useTransactionObservation_UNSTABLE = Recoil_index_20;
3399exports.waitForAll = Recoil_index_25;
3400exports.waitForAny = Recoil_index_24;
3401exports.waitForNone = Recoil_index_23;