Comparing version 0.16.3 to 0.16.4
import type { Context } from 'react'; | ||
import type { AnyAtom, WritableAtom, Scope } from './types'; | ||
import type { NewAtomReceiver } from './vanilla'; | ||
import { State } from './vanilla'; | ||
import { createMutableSource } from './useMutableSource'; | ||
declare type MutableSource = ReturnType<typeof createMutableSource>; | ||
export declare type Store = [ | ||
mutableSource: MutableSource, | ||
updateAtom: <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void> | ||
declare type MutableSource<_Target> = ReturnType<typeof createMutableSource>; | ||
declare type UpdateAtom = <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void>; | ||
declare type StoreForProduction = [ | ||
stateMutableSource: MutableSource<State>, | ||
updateAtom: UpdateAtom | ||
]; | ||
export declare const createStore: (initialValues?: Iterable<readonly [AnyAtom, unknown]> | undefined, newAtomReceiver?: NewAtomReceiver | undefined) => Store; | ||
export declare type StoreForDevelopment = [ | ||
stateMutableSource: MutableSource<State>, | ||
updateAtom: UpdateAtom, | ||
atomsMutableSource: MutableSource<{ | ||
atoms: AnyAtom[]; | ||
listeners: Set<() => void>; | ||
}> | ||
]; | ||
export declare type Store = StoreForProduction | StoreForDevelopment; | ||
declare type CreateStore = (initialValues?: Iterable<readonly [AnyAtom, unknown]>) => Store; | ||
export declare const createStore: CreateStore; | ||
declare type StoreContext = Context<Store>; | ||
export declare const getStoreContext: (scope?: Scope | undefined) => StoreContext; | ||
export {}; |
import React from 'react'; | ||
import type { AnyAtom, Scope } from './types'; | ||
import type { AtomState, State } from './vanilla'; | ||
export declare const Provider: React.FC<{ | ||
@@ -7,1 +8,18 @@ initialValues?: Iterable<readonly [AnyAtom, unknown]>; | ||
}>; | ||
export declare const getDevState: (state: State) => { | ||
n?: ((newAtom: AnyAtom) => void) | undefined; | ||
v: number; | ||
a: WeakMap<AnyAtom, AtomState<unknown>>; | ||
m: WeakMap<AnyAtom, { | ||
l: Set<() => void>; | ||
d: Set<AnyAtom>; | ||
u: void | import("./types").OnUnmount; | ||
}>; | ||
p: Set<AnyAtom>; | ||
}; | ||
export declare const getDevAtoms: ({ atoms }: { | ||
atoms: AnyAtom[]; | ||
}) => AnyAtom[]; | ||
export declare const subscribeDevAtoms: ({ listeners }: { | ||
listeners: Set<() => void>; | ||
}, callback: () => void) => () => boolean; |
@@ -31,3 +31,3 @@ import type { Atom, WritableAtom, AnyAtom, OnUnmount } from './types'; | ||
declare type MountedMap = WeakMap<AnyAtom, Mounted>; | ||
export declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type StateVersion = number; | ||
@@ -34,0 +34,0 @@ declare type PendingAtoms = Set<AnyAtom>; |
export { useAtomDevtools } from './devtools/useAtomDevtools'; | ||
export { useAtomsSnapshot } from './devtools/useAtomsSnapshot'; |
700
devtools.js
@@ -35,3 +35,3 @@ 'use strict'; | ||
var unsubscribe = devtools.current.subscribe(function (message) { | ||
var _message$payload3; | ||
var _message$payload3, _message$payload4; | ||
@@ -50,2 +50,19 @@ if (message.type === 'DISPATCH' && message.state) { | ||
(_devtools$current = devtools.current) == null ? void 0 : _devtools$current.init(lastValue.current); | ||
} else if (message.type === 'DISPATCH' && ((_message$payload4 = message.payload) == null ? void 0 : _message$payload4.type) === 'IMPORT_STATE') { | ||
var _message$payload$next, _message$payload$next2; | ||
var actions = (_message$payload$next = message.payload.nextLiftedState) == null ? void 0 : _message$payload$next.actionsById; | ||
var computedStates = ((_message$payload$next2 = message.payload.nextLiftedState) == null ? void 0 : _message$payload$next2.computedStates) || []; | ||
computedStates.forEach(function (_ref, index) { | ||
var state = _ref.state; | ||
actions[index] || atomName; | ||
if (index === 0) { | ||
var _devtools$current2; | ||
(_devtools$current2 = devtools.current) == null ? void 0 : _devtools$current2.init(state); | ||
} else { | ||
setValue(state); | ||
} | ||
}); | ||
} | ||
@@ -73,2 +90,683 @@ }); | ||
function _extends() { | ||
_extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
return _extends.apply(this, arguments); | ||
} | ||
var hasInitialValue = function hasInitialValue(atom) { | ||
return 'init' in atom; | ||
}; | ||
var IS_EQUAL_PROMISE = Symbol(); | ||
var INTERRUPT_PROMISE = Symbol(); | ||
var isInterruptablePromise = function isInterruptablePromise(promise) { | ||
return !!promise[INTERRUPT_PROMISE]; | ||
}; | ||
var createInterruptablePromise = function createInterruptablePromise(promise) { | ||
var interrupt; | ||
var interruptablePromise = new Promise(function (resolve, reject) { | ||
interrupt = resolve; | ||
promise.then(resolve, reject); | ||
}); | ||
interruptablePromise[IS_EQUAL_PROMISE] = function (p) { | ||
return p === interruptablePromise || p === promise; | ||
}; | ||
interruptablePromise[INTERRUPT_PROMISE] = interrupt; | ||
return interruptablePromise; | ||
}; | ||
var getAtomState = function getAtomState(state, atom) { | ||
return state.a.get(atom); | ||
}; | ||
var wipAtomState = function wipAtomState(state, atom, dependencies) { | ||
var atomState = getAtomState(state, atom); | ||
var nextAtomState = _extends({ | ||
r: 0 | ||
}, atomState, { | ||
d: dependencies ? new Map(Array.from(dependencies).map(function (a) { | ||
var _getAtomState$r, _getAtomState; | ||
return [a, (_getAtomState$r = (_getAtomState = getAtomState(state, a)) == null ? void 0 : _getAtomState.r) != null ? _getAtomState$r : 0]; | ||
})) : atomState ? atomState.d : new Map() | ||
}); | ||
return [nextAtomState, atomState == null ? void 0 : atomState.d]; | ||
}; | ||
var setAtomValue = function setAtomValue(state, atom, value, dependencies, promise) { | ||
var _atomState$p; | ||
var _wipAtomState = wipAtomState(state, atom, dependencies), | ||
atomState = _wipAtomState[0], | ||
prevDependencies = _wipAtomState[1]; | ||
if (promise && !((_atomState$p = atomState.p) != null && _atomState$p[IS_EQUAL_PROMISE](promise))) { | ||
return; | ||
} | ||
atomState.c == null ? void 0 : atomState.c(); | ||
delete atomState.e; | ||
delete atomState.p; | ||
delete atomState.c; | ||
delete atomState.i; | ||
if (!('v' in atomState) || !Object.is(atomState.v, value)) { | ||
atomState.v = value; | ||
++atomState.r; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
var setAtomReadError = function setAtomReadError(state, atom, error, dependencies, promise) { | ||
var _atomState$p2; | ||
var _wipAtomState2 = wipAtomState(state, atom, dependencies), | ||
atomState = _wipAtomState2[0], | ||
prevDependencies = _wipAtomState2[1]; | ||
if (promise && !((_atomState$p2 = atomState.p) != null && _atomState$p2[IS_EQUAL_PROMISE](promise))) { | ||
return; | ||
} | ||
atomState.c == null ? void 0 : atomState.c(); | ||
delete atomState.p; | ||
delete atomState.c; | ||
delete atomState.i; | ||
atomState.e = error; | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
var setAtomReadPromise = function setAtomReadPromise(state, atom, promise, dependencies) { | ||
var _atomState$p3; | ||
var _wipAtomState3 = wipAtomState(state, atom, dependencies), | ||
atomState = _wipAtomState3[0], | ||
prevDependencies = _wipAtomState3[1]; | ||
if ((_atomState$p3 = atomState.p) != null && _atomState$p3[IS_EQUAL_PROMISE](promise)) { | ||
return; | ||
} | ||
atomState.c == null ? void 0 : atomState.c(); | ||
if (isInterruptablePromise(promise)) { | ||
atomState.p = promise; | ||
delete atomState.c; | ||
} else { | ||
var interruptablePromise = createInterruptablePromise(promise); | ||
atomState.p = interruptablePromise; | ||
atomState.c = interruptablePromise[INTERRUPT_PROMISE]; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
var setAtomInvalidated = function setAtomInvalidated(state, atom) { | ||
var _wipAtomState4 = wipAtomState(state, atom), | ||
atomState = _wipAtomState4[0]; | ||
atomState.c == null ? void 0 : atomState.c(); | ||
delete atomState.p; | ||
delete atomState.c; | ||
atomState.i = atomState.r; | ||
commitAtomState(state, atom, atomState); | ||
}; | ||
var setAtomWritePromise = function setAtomWritePromise(state, atom, promise) { | ||
var _wipAtomState5 = wipAtomState(state, atom), | ||
atomState = _wipAtomState5[0]; | ||
if (promise) { | ||
atomState.w = promise; | ||
} else { | ||
delete atomState.w; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
}; | ||
var scheduleReadAtomState = function scheduleReadAtomState(state, atom, promise) { | ||
promise.finally(function () { | ||
readAtomState(state, atom, true); | ||
}); | ||
}; | ||
var readAtomState = function readAtomState(state, atom, force) { | ||
if (!force) { | ||
var atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
atomState.d.forEach(function (_, a) { | ||
if (a !== atom) { | ||
var aState = getAtomState(state, a); | ||
if (aState && !aState.e && !aState.p && aState.r === aState.i) { | ||
readAtomState(state, a, true); | ||
} | ||
} | ||
}); | ||
if (Array.from(atomState.d.entries()).every(function (_ref) { | ||
var a = _ref[0], | ||
r = _ref[1]; | ||
var aState = getAtomState(state, a); | ||
return aState && !aState.e && !aState.p && aState.r !== aState.i && aState.r === r; | ||
})) { | ||
return atomState; | ||
} | ||
} | ||
} | ||
var error; | ||
var promise; | ||
var value; | ||
var dependencies = new Set(); | ||
try { | ||
var promiseOrValue = atom.read(function (a) { | ||
dependencies.add(a); | ||
if (a !== atom) { | ||
var _aState = readAtomState(state, a); | ||
if (_aState.e) { | ||
throw _aState.e; | ||
} | ||
if (_aState.p) { | ||
throw _aState.p; | ||
} | ||
return _aState.v; | ||
} | ||
var aState = getAtomState(state, a); | ||
if (aState) { | ||
if (aState.p) { | ||
throw aState.p; | ||
} | ||
return aState.v; | ||
} | ||
if (hasInitialValue(a)) { | ||
return a.init; | ||
} | ||
throw new Error('no atom init'); | ||
}); | ||
if (promiseOrValue instanceof Promise) { | ||
promise = promiseOrValue.then(function (value) { | ||
setAtomValue(state, atom, value, dependencies, promise); | ||
flushPending(state); | ||
}).catch(function (e) { | ||
if (e instanceof Promise) { | ||
scheduleReadAtomState(state, atom, e); | ||
return e; | ||
} | ||
setAtomReadError(state, atom, e instanceof Error ? e : new Error(e), dependencies, promise); | ||
flushPending(state); | ||
}); | ||
} else { | ||
value = promiseOrValue; | ||
} | ||
} catch (errorOrPromise) { | ||
if (errorOrPromise instanceof Promise) { | ||
promise = errorOrPromise; | ||
} else if (errorOrPromise instanceof Error) { | ||
error = errorOrPromise; | ||
} else { | ||
error = new Error(errorOrPromise); | ||
} | ||
} | ||
if (error) { | ||
setAtomReadError(state, atom, error, dependencies); | ||
} else if (promise) { | ||
setAtomReadPromise(state, atom, promise, dependencies); | ||
} else { | ||
setAtomValue(state, atom, value, dependencies); | ||
} | ||
return getAtomState(state, atom); | ||
}; | ||
var addAtom = function addAtom(state, addingAtom) { | ||
var mounted = state.m.get(addingAtom); | ||
if (!mounted) { | ||
mounted = mountAtom(state, addingAtom); | ||
} | ||
flushPending(state); | ||
return mounted; | ||
}; | ||
var canUnmountAtom = function canUnmountAtom(atom, mounted) { | ||
return !mounted.l.size && (!mounted.d.size || mounted.d.size === 1 && mounted.d.has(atom)); | ||
}; | ||
var delAtom = function delAtom(state, deletingAtom) { | ||
var mounted = state.m.get(deletingAtom); | ||
if (mounted && canUnmountAtom(deletingAtom, mounted)) { | ||
unmountAtom(state, deletingAtom); | ||
} | ||
flushPending(state); | ||
}; | ||
var invalidateDependents = function invalidateDependents(state, atom) { | ||
var mounted = state.m.get(atom); | ||
mounted == null ? void 0 : mounted.d.forEach(function (dependent) { | ||
if (dependent === atom) { | ||
return; | ||
} | ||
setAtomInvalidated(state, dependent); | ||
invalidateDependents(state, dependent); | ||
}); | ||
}; | ||
var writeAtomState = function writeAtomState(state, atom, update, pendingPromises) { | ||
var isPendingPromisesExpired = !pendingPromises.length; | ||
var atomState = getAtomState(state, atom); | ||
if (atomState && atomState.w) { | ||
var promise = atomState.w.then(function () { | ||
writeAtomState(state, atom, update, pendingPromises); | ||
if (isPendingPromisesExpired) { | ||
flushPending(state); | ||
} | ||
}); | ||
if (!isPendingPromisesExpired) { | ||
pendingPromises.push(promise); | ||
} | ||
return; | ||
} | ||
try { | ||
var promiseOrVoid = atom.write(function (a) { | ||
var aState = readAtomState(state, a); | ||
if (aState.e) { | ||
throw aState.e; | ||
} | ||
if (aState.p) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('Reading pending atom state in write operation. We throw a promise for now.', a); | ||
} | ||
throw aState.p; | ||
} | ||
if ('v' in aState) { | ||
return aState.v; | ||
} | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('[Bug] no value found while reading atom in write operation. This probably a bug.', a); | ||
} | ||
throw new Error('no value found'); | ||
}, function (a, v) { | ||
var isPendingPromisesExpired = !pendingPromises.length; | ||
if (a === atom) { | ||
setAtomValue(state, a, v); | ||
invalidateDependents(state, a); | ||
} else { | ||
writeAtomState(state, a, v, pendingPromises); | ||
} | ||
if (isPendingPromisesExpired) { | ||
flushPending(state); | ||
} | ||
}, update); | ||
if (promiseOrVoid instanceof Promise) { | ||
var _promise = promiseOrVoid.finally(function () { | ||
setAtomWritePromise(state, atom); | ||
if (isPendingPromisesExpired) { | ||
flushPending(state); | ||
} | ||
}); | ||
if (!isPendingPromisesExpired) { | ||
pendingPromises.push(_promise); | ||
} | ||
setAtomWritePromise(state, atom, _promise); | ||
} | ||
} catch (e) { | ||
if (pendingPromises.length === 1) { | ||
throw e; | ||
} else if (!isPendingPromisesExpired) { | ||
pendingPromises.push(new Promise(function (_resolve, reject) { | ||
reject(e); | ||
})); | ||
} else { | ||
console.error('Uncaught exception: Use promise to catch error', e); | ||
} | ||
} | ||
}; | ||
var writeAtom = function writeAtom(state, writingAtom, update) { | ||
var pendingPromises = [Promise.resolve()]; | ||
writeAtomState(state, writingAtom, update, pendingPromises); | ||
flushPending(state); | ||
if (pendingPromises.length <= 1) { | ||
pendingPromises.splice(0); | ||
} else { | ||
return new Promise(function (resolve, reject) { | ||
var loop = function loop() { | ||
if (pendingPromises.length <= 1) { | ||
pendingPromises.splice(0); | ||
resolve(); | ||
} else { | ||
Promise.all(pendingPromises).then(function () { | ||
pendingPromises.splice(1); | ||
flushPending(state); | ||
loop(); | ||
}).catch(reject); | ||
} | ||
}; | ||
loop(); | ||
}); | ||
} | ||
}; | ||
var isActuallyWritableAtom = function isActuallyWritableAtom(atom) { | ||
return !!atom.write; | ||
}; | ||
var mountAtom = function mountAtom(state, atom, initialDependent) { | ||
var atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
atomState.d.forEach(function (_, a) { | ||
if (a !== atom) { | ||
if (!state.m.has(a)) { | ||
mountAtom(state, a, atom); | ||
} | ||
} | ||
}); | ||
} else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('[Bug] could not find atom state to mount', atom); | ||
} | ||
var mounted = { | ||
d: new Set(initialDependent && [initialDependent]), | ||
l: new Set(), | ||
u: undefined | ||
}; | ||
state.m.set(atom, mounted); | ||
if (isActuallyWritableAtom(atom) && atom.onMount) { | ||
var setAtom = function setAtom(update) { | ||
return writeAtom(state, atom, update); | ||
}; | ||
mounted.u = atom.onMount(setAtom); | ||
} | ||
return mounted; | ||
}; | ||
var unmountAtom = function unmountAtom(state, atom) { | ||
var _state$m$get; | ||
var onUnmount = (_state$m$get = state.m.get(atom)) == null ? void 0 : _state$m$get.u; | ||
if (onUnmount) { | ||
onUnmount(); | ||
} | ||
state.m.delete(atom); | ||
var atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
if (atomState.p && typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('[Bug] deleting atomState with read promise', atom); | ||
} | ||
atomState.d.forEach(function (_, a) { | ||
if (a !== atom) { | ||
var mounted = state.m.get(a); | ||
if (mounted) { | ||
mounted.d.delete(atom); | ||
if (canUnmountAtom(a, mounted)) { | ||
unmountAtom(state, a); | ||
} | ||
} | ||
} | ||
}); | ||
} else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('[Bug] could not find atom state to unmount', atom); | ||
} | ||
}; | ||
var mountDependencies = function mountDependencies(state, atom, atomState, prevDependencies) { | ||
if (prevDependencies !== atomState.d) { | ||
var dependencies = new Set(atomState.d.keys()); | ||
if (prevDependencies) { | ||
prevDependencies.forEach(function (_, a) { | ||
var mounted = state.m.get(a); | ||
if (dependencies.has(a)) { | ||
dependencies.delete(a); | ||
} else if (mounted) { | ||
mounted.d.delete(atom); | ||
if (canUnmountAtom(a, mounted)) { | ||
unmountAtom(state, a); | ||
} | ||
} else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
console.warn('[Bug] a dependency is not mounted', a); | ||
} | ||
}); | ||
} | ||
dependencies.forEach(function (a) { | ||
var mounted = state.m.get(a); | ||
if (mounted) { | ||
var dependents = mounted.d; | ||
dependents.add(atom); | ||
} else { | ||
mountAtom(state, a, atom); | ||
} | ||
}); | ||
} | ||
}; | ||
var commitAtomState = function commitAtomState(state, atom, atomState) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
Object.freeze(atomState); | ||
} | ||
var isNewAtom = state.n && !state.a.has(atom); | ||
state.a.set(atom, atomState); | ||
if (isNewAtom) { | ||
state.n(atom); | ||
} | ||
++state.v; | ||
state.p.add(atom); | ||
}; | ||
var flushPending = function flushPending(state) { | ||
state.p.forEach(function (atom) { | ||
var mounted = state.m.get(atom); | ||
mounted == null ? void 0 : mounted.l.forEach(function (listener) { | ||
return listener(); | ||
}); | ||
}); | ||
state.p.clear(); | ||
}; | ||
var subscribeAtom = function subscribeAtom(state, atom, callback) { | ||
var mounted = addAtom(state, atom); | ||
var listeners = mounted.l; | ||
listeners.add(callback); | ||
return function () { | ||
listeners.delete(callback); | ||
delAtom(state, atom); | ||
}; | ||
}; | ||
var TARGET = Symbol(); | ||
var GET_VERSION = Symbol(); | ||
var useMutableSource = function useMutableSource(source, getSnapshot, subscribe) { | ||
var lastVersion = react.useRef(0); | ||
var currentVersion = source[GET_VERSION](source[TARGET]); | ||
var _useState = react.useState(function () { | ||
return [source, getSnapshot, subscribe, currentVersion, getSnapshot(source[TARGET])]; | ||
}), | ||
state = _useState[0], | ||
setState = _useState[1]; | ||
var currentSnapshot = state[4]; | ||
if (state[0] !== source || state[1] !== getSnapshot || state[2] !== subscribe) { | ||
currentSnapshot = getSnapshot(source[TARGET]); | ||
setState([source, getSnapshot, subscribe, currentVersion, currentSnapshot]); | ||
} else if (currentVersion !== state[3] && currentVersion !== lastVersion.current) { | ||
currentSnapshot = getSnapshot(source[TARGET]); | ||
if (!Object.is(currentSnapshot, state[4])) { | ||
setState([source, getSnapshot, subscribe, currentVersion, currentSnapshot]); | ||
} | ||
} | ||
react.useEffect(function () { | ||
var didUnsubscribe = false; | ||
var checkForUpdates = function checkForUpdates() { | ||
if (didUnsubscribe) { | ||
return; | ||
} | ||
try { | ||
var nextSnapshot = getSnapshot(source[TARGET]); | ||
var nextVersion = source[GET_VERSION](source[TARGET]); | ||
lastVersion.current = nextVersion; | ||
setState(function (prev) { | ||
if (prev[0] !== source || prev[1] !== getSnapshot || prev[2] !== subscribe) { | ||
return prev; | ||
} | ||
if (Object.is(prev[4], nextSnapshot)) { | ||
return prev; | ||
} | ||
return [prev[0], prev[1], prev[2], nextVersion, nextSnapshot]; | ||
}); | ||
} catch (e) { | ||
setState(function (prev) { | ||
return [].concat(prev); | ||
}); | ||
} | ||
}; | ||
var unsubscribe = subscribe(source[TARGET], checkForUpdates); | ||
checkForUpdates(); | ||
return function () { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [source, getSnapshot, subscribe]); | ||
return currentSnapshot; | ||
}; | ||
var getDevState = function getDevState(state) { | ||
return _extends({}, state); | ||
}; | ||
var getDevAtoms = function getDevAtoms(_ref3) { | ||
var atoms = _ref3.atoms; | ||
return atoms; | ||
}; | ||
var subscribeDevAtoms = function subscribeDevAtoms(_ref4, callback) { | ||
var listeners = _ref4.listeners; | ||
listeners.add(callback); | ||
return function () { | ||
return listeners.delete(callback); | ||
}; | ||
}; | ||
function useAtomsSnapshot() { | ||
var StoreContext = jotai.SECRET_INTERNAL_getStoreContext(); | ||
var _useContext = react.useContext(StoreContext), | ||
mutableSource = _useContext[0], | ||
atomsMutableSource = _useContext[2]; | ||
if (atomsMutableSource === undefined) { | ||
throw Error('useAtomsSnapshot can only be used in dev mode.'); | ||
} | ||
var atoms = useMutableSource(atomsMutableSource, getDevAtoms, subscribeDevAtoms); | ||
var subscribe = react.useCallback(function (state, callback) { | ||
var unsubs = atoms.map(function (atom) { | ||
return subscribeAtom(state, atom, callback); | ||
}); | ||
return function () { | ||
unsubs.forEach(function (unsub) { | ||
return unsub(); | ||
}); | ||
}; | ||
}, [atoms]); | ||
var state = useMutableSource(mutableSource, getDevState, subscribe); | ||
return react.useMemo(function () { | ||
var atomToAtomValueTuples = atoms.filter(function (atom) { | ||
return !!state.m.get(atom); | ||
}).map(function (atom) { | ||
var _state$a$get; | ||
var atomState = (_state$a$get = state.a.get(atom)) != null ? _state$a$get : {}; | ||
return [atom, atomState.e || atomState.p || atomState.w || atomState.v]; | ||
}); | ||
return new Map(atomToAtomValueTuples); | ||
}, [atoms, state]); | ||
} | ||
exports.useAtomDevtools = useAtomDevtools; | ||
exports.useAtomsSnapshot = useAtomsSnapshot; |
import type { Context } from 'react'; | ||
import type { AnyAtom, WritableAtom, Scope } from './types'; | ||
import type { NewAtomReceiver } from './vanilla'; | ||
import { State } from './vanilla'; | ||
import { createMutableSource } from './useMutableSource'; | ||
declare type MutableSource = ReturnType<typeof createMutableSource>; | ||
export declare type Store = [ | ||
mutableSource: MutableSource, | ||
updateAtom: <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void> | ||
declare type MutableSource<_Target> = ReturnType<typeof createMutableSource>; | ||
declare type UpdateAtom = <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void>; | ||
declare type StoreForProduction = [ | ||
stateMutableSource: MutableSource<State>, | ||
updateAtom: UpdateAtom | ||
]; | ||
export declare const createStore: (initialValues?: Iterable<readonly [AnyAtom, unknown]> | undefined, newAtomReceiver?: NewAtomReceiver | undefined) => Store; | ||
export declare type StoreForDevelopment = [ | ||
stateMutableSource: MutableSource<State>, | ||
updateAtom: UpdateAtom, | ||
atomsMutableSource: MutableSource<{ | ||
atoms: AnyAtom[]; | ||
listeners: Set<() => void>; | ||
}> | ||
]; | ||
export declare type Store = StoreForProduction | StoreForDevelopment; | ||
declare type CreateStore = (initialValues?: Iterable<readonly [AnyAtom, unknown]>) => Store; | ||
export declare const createStore: CreateStore; | ||
declare type StoreContext = Context<Store>; | ||
export declare const getStoreContext: (scope?: Scope | undefined) => StoreContext; | ||
export {}; |
import React from 'react'; | ||
import type { AnyAtom, Scope } from './types'; | ||
import type { AtomState, State } from './vanilla'; | ||
export declare const Provider: React.FC<{ | ||
@@ -7,1 +8,18 @@ initialValues?: Iterable<readonly [AnyAtom, unknown]>; | ||
}>; | ||
export declare const getDevState: (state: State) => { | ||
n?: ((newAtom: AnyAtom) => void) | undefined; | ||
v: number; | ||
a: WeakMap<AnyAtom, AtomState<unknown>>; | ||
m: WeakMap<AnyAtom, { | ||
l: Set<() => void>; | ||
d: Set<AnyAtom>; | ||
u: void | import("./types").OnUnmount; | ||
}>; | ||
p: Set<AnyAtom>; | ||
}; | ||
export declare const getDevAtoms: ({ atoms }: { | ||
atoms: AnyAtom[]; | ||
}) => AnyAtom[]; | ||
export declare const subscribeDevAtoms: ({ listeners }: { | ||
listeners: Set<() => void>; | ||
}, callback: () => void) => () => boolean; |
@@ -31,3 +31,3 @@ import type { Atom, WritableAtom, AnyAtom, OnUnmount } from './types'; | ||
declare type MountedMap = WeakMap<AnyAtom, Mounted>; | ||
export declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type StateVersion = number; | ||
@@ -34,0 +34,0 @@ declare type PendingAtoms = Set<AnyAtom>; |
export { useAtomDevtools } from './devtools/useAtomDevtools'; | ||
export { useAtomsSnapshot } from './devtools/useAtomsSnapshot'; |
@@ -1,3 +0,3 @@ | ||
import { useRef, useEffect } from 'react'; | ||
import { useAtom } from 'jotai'; | ||
import { useRef, useEffect, useState, useContext, useCallback, useMemo } from 'react'; | ||
import { useAtom, SECRET_INTERNAL_getStoreContext } from 'jotai'; | ||
@@ -24,3 +24,3 @@ function useAtomDevtools(anAtom, name) { | ||
const unsubscribe = devtools.current.subscribe((message) => { | ||
var _a, _b, _c, _d; | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
if (message.type === "DISPATCH" && message.state) { | ||
@@ -33,2 +33,14 @@ if (((_a = message.payload) == null ? void 0 : _a.type) === "JUMP_TO_ACTION" || ((_b = message.payload) == null ? void 0 : _b.type) === "JUMP_TO_STATE") { | ||
(_d = devtools.current) == null ? void 0 : _d.init(lastValue.current); | ||
} else if (message.type === "DISPATCH" && ((_e = message.payload) == null ? void 0 : _e.type) === "IMPORT_STATE") { | ||
const actions = (_f = message.payload.nextLiftedState) == null ? void 0 : _f.actionsById; | ||
const computedStates = ((_g = message.payload.nextLiftedState) == null ? void 0 : _g.computedStates) || []; | ||
computedStates.forEach(({state}, index) => { | ||
var _a2; | ||
actions[index] || atomName; | ||
if (index === 0) { | ||
(_a2 = devtools.current) == null ? void 0 : _a2.init(state); | ||
} else { | ||
setValue(state); | ||
} | ||
}); | ||
} | ||
@@ -55,2 +67,554 @@ }); | ||
export { useAtomDevtools }; | ||
var __defProp$1 = Object.defineProperty; | ||
var __hasOwnProp$1 = Object.prototype.hasOwnProperty; | ||
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; | ||
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {enumerable: true, configurable: true, writable: true, value}) : obj[key] = value; | ||
var __objSpread$1 = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
if (__getOwnPropSymbols$1) | ||
for (var prop of __getOwnPropSymbols$1(b)) { | ||
if (__propIsEnum$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
const hasInitialValue = (atom) => "init" in atom; | ||
const IS_EQUAL_PROMISE = Symbol(); | ||
const INTERRUPT_PROMISE = Symbol(); | ||
const isInterruptablePromise = (promise) => !!promise[INTERRUPT_PROMISE]; | ||
const createInterruptablePromise = (promise) => { | ||
let interrupt; | ||
const interruptablePromise = new Promise((resolve, reject) => { | ||
interrupt = resolve; | ||
promise.then(resolve, reject); | ||
}); | ||
interruptablePromise[IS_EQUAL_PROMISE] = (p) => p === interruptablePromise || p === promise; | ||
interruptablePromise[INTERRUPT_PROMISE] = interrupt; | ||
return interruptablePromise; | ||
}; | ||
const getAtomState = (state, atom) => state.a.get(atom); | ||
const wipAtomState = (state, atom, dependencies) => { | ||
const atomState = getAtomState(state, atom); | ||
const nextAtomState = __objSpread$1(__objSpread$1({ | ||
r: 0 | ||
}, atomState), { | ||
d: dependencies ? new Map(Array.from(dependencies).map((a) => { | ||
var _a, _b; | ||
return [ | ||
a, | ||
(_b = (_a = getAtomState(state, a)) == null ? void 0 : _a.r) != null ? _b : 0 | ||
]; | ||
})) : atomState ? atomState.d : new Map() | ||
}); | ||
return [nextAtomState, atomState == null ? void 0 : atomState.d]; | ||
}; | ||
const setAtomValue = (state, atom, value, dependencies, promise) => { | ||
var _a, _b; | ||
const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); | ||
if (promise && !((_a = atomState.p) == null ? void 0 : _a[IS_EQUAL_PROMISE](promise))) { | ||
return; | ||
} | ||
(_b = atomState.c) == null ? void 0 : _b.call(atomState); | ||
delete atomState.e; | ||
delete atomState.p; | ||
delete atomState.c; | ||
delete atomState.i; | ||
if (!("v" in atomState) || !Object.is(atomState.v, value)) { | ||
atomState.v = value; | ||
++atomState.r; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
const setAtomReadError = (state, atom, error, dependencies, promise) => { | ||
var _a, _b; | ||
const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); | ||
if (promise && !((_a = atomState.p) == null ? void 0 : _a[IS_EQUAL_PROMISE](promise))) { | ||
return; | ||
} | ||
(_b = atomState.c) == null ? void 0 : _b.call(atomState); | ||
delete atomState.p; | ||
delete atomState.c; | ||
delete atomState.i; | ||
atomState.e = error; | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
const setAtomReadPromise = (state, atom, promise, dependencies) => { | ||
var _a, _b; | ||
const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); | ||
if ((_a = atomState.p) == null ? void 0 : _a[IS_EQUAL_PROMISE](promise)) { | ||
return; | ||
} | ||
(_b = atomState.c) == null ? void 0 : _b.call(atomState); | ||
if (isInterruptablePromise(promise)) { | ||
atomState.p = promise; | ||
delete atomState.c; | ||
} else { | ||
const interruptablePromise = createInterruptablePromise(promise); | ||
atomState.p = interruptablePromise; | ||
atomState.c = interruptablePromise[INTERRUPT_PROMISE]; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
mountDependencies(state, atom, atomState, prevDependencies); | ||
}; | ||
const setAtomInvalidated = (state, atom) => { | ||
var _a; | ||
const [atomState] = wipAtomState(state, atom); | ||
(_a = atomState.c) == null ? void 0 : _a.call(atomState); | ||
delete atomState.p; | ||
delete atomState.c; | ||
atomState.i = atomState.r; | ||
commitAtomState(state, atom, atomState); | ||
}; | ||
const setAtomWritePromise = (state, atom, promise) => { | ||
const [atomState] = wipAtomState(state, atom); | ||
if (promise) { | ||
atomState.w = promise; | ||
} else { | ||
delete atomState.w; | ||
} | ||
commitAtomState(state, atom, atomState); | ||
}; | ||
const scheduleReadAtomState = (state, atom, promise) => { | ||
promise.finally(() => { | ||
readAtomState(state, atom, true); | ||
}); | ||
}; | ||
const readAtomState = (state, atom, force) => { | ||
if (!force) { | ||
const atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
atomState.d.forEach((_, a) => { | ||
if (a !== atom) { | ||
const aState = getAtomState(state, a); | ||
if (aState && !aState.e && !aState.p && aState.r === aState.i) { | ||
readAtomState(state, a, true); | ||
} | ||
} | ||
}); | ||
if (Array.from(atomState.d.entries()).every(([a, r]) => { | ||
const aState = getAtomState(state, a); | ||
return aState && !aState.e && !aState.p && aState.r !== aState.i && aState.r === r; | ||
})) { | ||
return atomState; | ||
} | ||
} | ||
} | ||
let error; | ||
let promise; | ||
let value; | ||
const dependencies = new Set(); | ||
try { | ||
const promiseOrValue = atom.read((a) => { | ||
dependencies.add(a); | ||
if (a !== atom) { | ||
const aState2 = readAtomState(state, a); | ||
if (aState2.e) { | ||
throw aState2.e; | ||
} | ||
if (aState2.p) { | ||
throw aState2.p; | ||
} | ||
return aState2.v; | ||
} | ||
const aState = getAtomState(state, a); | ||
if (aState) { | ||
if (aState.p) { | ||
throw aState.p; | ||
} | ||
return aState.v; | ||
} | ||
if (hasInitialValue(a)) { | ||
return a.init; | ||
} | ||
throw new Error("no atom init"); | ||
}); | ||
if (promiseOrValue instanceof Promise) { | ||
promise = promiseOrValue.then((value2) => { | ||
setAtomValue(state, atom, value2, dependencies, promise); | ||
flushPending(state); | ||
}).catch((e) => { | ||
if (e instanceof Promise) { | ||
scheduleReadAtomState(state, atom, e); | ||
return e; | ||
} | ||
setAtomReadError(state, atom, e instanceof Error ? e : new Error(e), dependencies, promise); | ||
flushPending(state); | ||
}); | ||
} else { | ||
value = promiseOrValue; | ||
} | ||
} catch (errorOrPromise) { | ||
if (errorOrPromise instanceof Promise) { | ||
promise = errorOrPromise; | ||
} else if (errorOrPromise instanceof Error) { | ||
error = errorOrPromise; | ||
} else { | ||
error = new Error(errorOrPromise); | ||
} | ||
} | ||
if (error) { | ||
setAtomReadError(state, atom, error, dependencies); | ||
} else if (promise) { | ||
setAtomReadPromise(state, atom, promise, dependencies); | ||
} else { | ||
setAtomValue(state, atom, value, dependencies); | ||
} | ||
return getAtomState(state, atom); | ||
}; | ||
const addAtom = (state, addingAtom) => { | ||
let mounted = state.m.get(addingAtom); | ||
if (!mounted) { | ||
mounted = mountAtom(state, addingAtom); | ||
} | ||
flushPending(state); | ||
return mounted; | ||
}; | ||
const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.d.size || mounted.d.size === 1 && mounted.d.has(atom)); | ||
const delAtom = (state, deletingAtom) => { | ||
const mounted = state.m.get(deletingAtom); | ||
if (mounted && canUnmountAtom(deletingAtom, mounted)) { | ||
unmountAtom(state, deletingAtom); | ||
} | ||
flushPending(state); | ||
}; | ||
const invalidateDependents = (state, atom) => { | ||
const mounted = state.m.get(atom); | ||
mounted == null ? void 0 : mounted.d.forEach((dependent) => { | ||
if (dependent === atom) { | ||
return; | ||
} | ||
setAtomInvalidated(state, dependent); | ||
invalidateDependents(state, dependent); | ||
}); | ||
}; | ||
const writeAtomState = (state, atom, update, pendingPromises) => { | ||
const isPendingPromisesExpired = !pendingPromises.length; | ||
const atomState = getAtomState(state, atom); | ||
if (atomState && atomState.w) { | ||
const promise = atomState.w.then(() => { | ||
writeAtomState(state, atom, update, pendingPromises); | ||
if (isPendingPromisesExpired) { | ||
flushPending(state); | ||
} | ||
}); | ||
if (!isPendingPromisesExpired) { | ||
pendingPromises.push(promise); | ||
} | ||
return; | ||
} | ||
try { | ||
const promiseOrVoid = atom.write((a) => { | ||
const aState = readAtomState(state, a); | ||
if (aState.e) { | ||
throw aState.e; | ||
} | ||
if (aState.p) { | ||
if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("Reading pending atom state in write operation. We throw a promise for now.", a); | ||
} | ||
throw aState.p; | ||
} | ||
if ("v" in aState) { | ||
return aState.v; | ||
} | ||
if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("[Bug] no value found while reading atom in write operation. This probably a bug.", a); | ||
} | ||
throw new Error("no value found"); | ||
}, (a, v) => { | ||
const isPendingPromisesExpired2 = !pendingPromises.length; | ||
if (a === atom) { | ||
setAtomValue(state, a, v); | ||
invalidateDependents(state, a); | ||
} else { | ||
writeAtomState(state, a, v, pendingPromises); | ||
} | ||
if (isPendingPromisesExpired2) { | ||
flushPending(state); | ||
} | ||
}, update); | ||
if (promiseOrVoid instanceof Promise) { | ||
const promise = promiseOrVoid.finally(() => { | ||
setAtomWritePromise(state, atom); | ||
if (isPendingPromisesExpired) { | ||
flushPending(state); | ||
} | ||
}); | ||
if (!isPendingPromisesExpired) { | ||
pendingPromises.push(promise); | ||
} | ||
setAtomWritePromise(state, atom, promise); | ||
} | ||
} catch (e) { | ||
if (pendingPromises.length === 1) { | ||
throw e; | ||
} else if (!isPendingPromisesExpired) { | ||
pendingPromises.push(new Promise((_resolve, reject) => { | ||
reject(e); | ||
})); | ||
} else { | ||
console.error("Uncaught exception: Use promise to catch error", e); | ||
} | ||
} | ||
}; | ||
const writeAtom = (state, writingAtom, update) => { | ||
const pendingPromises = [Promise.resolve()]; | ||
writeAtomState(state, writingAtom, update, pendingPromises); | ||
flushPending(state); | ||
if (pendingPromises.length <= 1) { | ||
pendingPromises.splice(0); | ||
} else { | ||
return new Promise((resolve, reject) => { | ||
const loop = () => { | ||
if (pendingPromises.length <= 1) { | ||
pendingPromises.splice(0); | ||
resolve(); | ||
} else { | ||
Promise.all(pendingPromises).then(() => { | ||
pendingPromises.splice(1); | ||
flushPending(state); | ||
loop(); | ||
}).catch(reject); | ||
} | ||
}; | ||
loop(); | ||
}); | ||
} | ||
}; | ||
const isActuallyWritableAtom = (atom) => !!atom.write; | ||
const mountAtom = (state, atom, initialDependent) => { | ||
const atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
atomState.d.forEach((_, a) => { | ||
if (a !== atom) { | ||
if (!state.m.has(a)) { | ||
mountAtom(state, a, atom); | ||
} | ||
} | ||
}); | ||
} else if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("[Bug] could not find atom state to mount", atom); | ||
} | ||
const mounted = { | ||
d: new Set(initialDependent && [initialDependent]), | ||
l: new Set(), | ||
u: void 0 | ||
}; | ||
state.m.set(atom, mounted); | ||
if (isActuallyWritableAtom(atom) && atom.onMount) { | ||
const setAtom = (update) => writeAtom(state, atom, update); | ||
mounted.u = atom.onMount(setAtom); | ||
} | ||
return mounted; | ||
}; | ||
const unmountAtom = (state, atom) => { | ||
var _a; | ||
const onUnmount = (_a = state.m.get(atom)) == null ? void 0 : _a.u; | ||
if (onUnmount) { | ||
onUnmount(); | ||
} | ||
state.m.delete(atom); | ||
const atomState = getAtomState(state, atom); | ||
if (atomState) { | ||
if (atomState.p && typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("[Bug] deleting atomState with read promise", atom); | ||
} | ||
atomState.d.forEach((_, a) => { | ||
if (a !== atom) { | ||
const mounted = state.m.get(a); | ||
if (mounted) { | ||
mounted.d.delete(atom); | ||
if (canUnmountAtom(a, mounted)) { | ||
unmountAtom(state, a); | ||
} | ||
} | ||
} | ||
}); | ||
} else if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("[Bug] could not find atom state to unmount", atom); | ||
} | ||
}; | ||
const mountDependencies = (state, atom, atomState, prevDependencies) => { | ||
if (prevDependencies !== atomState.d) { | ||
const dependencies = new Set(atomState.d.keys()); | ||
if (prevDependencies) { | ||
prevDependencies.forEach((_, a) => { | ||
const mounted = state.m.get(a); | ||
if (dependencies.has(a)) { | ||
dependencies.delete(a); | ||
} else if (mounted) { | ||
mounted.d.delete(atom); | ||
if (canUnmountAtom(a, mounted)) { | ||
unmountAtom(state, a); | ||
} | ||
} else if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
console.warn("[Bug] a dependency is not mounted", a); | ||
} | ||
}); | ||
} | ||
dependencies.forEach((a) => { | ||
const mounted = state.m.get(a); | ||
if (mounted) { | ||
const dependents = mounted.d; | ||
dependents.add(atom); | ||
} else { | ||
mountAtom(state, a, atom); | ||
} | ||
}); | ||
} | ||
}; | ||
const commitAtomState = (state, atom, atomState) => { | ||
if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
Object.freeze(atomState); | ||
} | ||
const isNewAtom = state.n && !state.a.has(atom); | ||
state.a.set(atom, atomState); | ||
if (isNewAtom) { | ||
state.n(atom); | ||
} | ||
++state.v; | ||
state.p.add(atom); | ||
}; | ||
const flushPending = (state) => { | ||
state.p.forEach((atom) => { | ||
const mounted = state.m.get(atom); | ||
mounted == null ? void 0 : mounted.l.forEach((listener) => listener()); | ||
}); | ||
state.p.clear(); | ||
}; | ||
const subscribeAtom = (state, atom, callback) => { | ||
const mounted = addAtom(state, atom); | ||
const listeners = mounted.l; | ||
listeners.add(callback); | ||
return () => { | ||
listeners.delete(callback); | ||
delAtom(state, atom); | ||
}; | ||
}; | ||
const TARGET = Symbol(); | ||
const GET_VERSION = Symbol(); | ||
const useMutableSource = (source, getSnapshot, subscribe) => { | ||
const lastVersion = useRef(0); | ||
const currentVersion = source[GET_VERSION](source[TARGET]); | ||
const [state, setState] = useState(() => [ | ||
source, | ||
getSnapshot, | ||
subscribe, | ||
currentVersion, | ||
getSnapshot(source[TARGET]) | ||
]); | ||
let currentSnapshot = state[4]; | ||
if (state[0] !== source || state[1] !== getSnapshot || state[2] !== subscribe) { | ||
currentSnapshot = getSnapshot(source[TARGET]); | ||
setState([ | ||
source, | ||
getSnapshot, | ||
subscribe, | ||
currentVersion, | ||
currentSnapshot | ||
]); | ||
} else if (currentVersion !== state[3] && currentVersion !== lastVersion.current) { | ||
currentSnapshot = getSnapshot(source[TARGET]); | ||
if (!Object.is(currentSnapshot, state[4])) { | ||
setState([ | ||
source, | ||
getSnapshot, | ||
subscribe, | ||
currentVersion, | ||
currentSnapshot | ||
]); | ||
} | ||
} | ||
useEffect(() => { | ||
let didUnsubscribe = false; | ||
const checkForUpdates = () => { | ||
if (didUnsubscribe) { | ||
return; | ||
} | ||
try { | ||
const nextSnapshot = getSnapshot(source[TARGET]); | ||
const nextVersion = source[GET_VERSION](source[TARGET]); | ||
lastVersion.current = nextVersion; | ||
setState((prev) => { | ||
if (prev[0] !== source || prev[1] !== getSnapshot || prev[2] !== subscribe) { | ||
return prev; | ||
} | ||
if (Object.is(prev[4], nextSnapshot)) { | ||
return prev; | ||
} | ||
return [ | ||
prev[0], | ||
prev[1], | ||
prev[2], | ||
nextVersion, | ||
nextSnapshot | ||
]; | ||
}); | ||
} catch (e) { | ||
setState((prev) => [...prev]); | ||
} | ||
}; | ||
const unsubscribe = subscribe(source[TARGET], checkForUpdates); | ||
checkForUpdates(); | ||
return () => { | ||
didUnsubscribe = true; | ||
unsubscribe(); | ||
}; | ||
}, [source, getSnapshot, subscribe]); | ||
return currentSnapshot; | ||
}; | ||
var __defProp = Object.defineProperty; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {enumerable: true, configurable: true, writable: true, value}) : obj[key] = value; | ||
var __objSpread = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
const getDevState = (state) => __objSpread({}, state); | ||
const getDevAtoms = ({atoms}) => atoms; | ||
const subscribeDevAtoms = ({listeners}, callback) => { | ||
listeners.add(callback); | ||
return () => listeners.delete(callback); | ||
}; | ||
function useAtomsSnapshot() { | ||
const StoreContext = SECRET_INTERNAL_getStoreContext(); | ||
const [mutableSource, , atomsMutableSource] = useContext(StoreContext); | ||
if (atomsMutableSource === void 0) { | ||
throw Error("useAtomsSnapshot can only be used in dev mode."); | ||
} | ||
const atoms = useMutableSource(atomsMutableSource, getDevAtoms, subscribeDevAtoms); | ||
const subscribe = useCallback((state2, callback) => { | ||
const unsubs = atoms.map((atom) => subscribeAtom(state2, atom, callback)); | ||
return () => { | ||
unsubs.forEach((unsub) => unsub()); | ||
}; | ||
}, [atoms]); | ||
const state = useMutableSource(mutableSource, getDevState, subscribe); | ||
return useMemo(() => { | ||
const atomToAtomValueTuples = atoms.filter((atom) => !!state.m.get(atom)).map((atom) => { | ||
var _a; | ||
const atomState = (_a = state.a.get(atom)) != null ? _a : {}; | ||
return [atom, atomState.e || atomState.p || atomState.w || atomState.v]; | ||
}); | ||
return new Map(atomToAtomValueTuples); | ||
}, [atoms, state]); | ||
} | ||
export { useAtomDevtools, useAtomsSnapshot }; |
@@ -207,3 +207,2 @@ import { useRef, useState, useEffect, createContext, createElement, useCallback, useDebugValue, useContext } from 'react'; | ||
if (errorOrPromise instanceof Promise) { | ||
scheduleReadAtomState(state, atom, errorOrPromise); | ||
promise = errorOrPromise; | ||
@@ -539,8 +538,23 @@ } else if (errorOrPromise instanceof Error) { | ||
const createStore = (initialValues, newAtomReceiver) => { | ||
const state = createState(initialValues, newAtomReceiver); | ||
const mutableSource = createMutableSource(state, () => state.v); | ||
const createStoreForProduction = (initialValues) => { | ||
const state = createState(initialValues); | ||
const stateMutableSource = createMutableSource(state, () => state.v); | ||
const updateAtom = (atom, update) => writeAtom(state, atom, update); | ||
return [mutableSource, updateAtom]; | ||
return [stateMutableSource, updateAtom]; | ||
}; | ||
const createStoreForDevelopment = (initialValues) => { | ||
const atomsStore = { | ||
atoms: [], | ||
listeners: new Set() | ||
}; | ||
const state = createState(initialValues, (newAtom) => { | ||
atomsStore.atoms = [...atomsStore.atoms, newAtom]; | ||
atomsStore.listeners.forEach((listener) => listener()); | ||
}); | ||
const stateMutableSource = createMutableSource(state, () => state.v); | ||
const updateAtom = (atom, update) => writeAtom(state, atom, update); | ||
const atomsMutableSource = createMutableSource(atomsStore, () => atomsStore.atoms); | ||
return [stateMutableSource, updateAtom, atomsMutableSource]; | ||
}; | ||
const createStore = typeof process === "object" && process.env.NODE_ENV !== "production" ? createStoreForDevelopment : createStoreForProduction; | ||
const StoreContextMap = new Map(); | ||
@@ -572,15 +586,8 @@ const getStoreContext = (scope) => { | ||
const storeRef = useRef(null); | ||
if (typeof process === "object" && process.env.NODE_ENV !== "production") { | ||
const atomsRef = useRef([]); | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues, (newAtom) => { | ||
atomsRef.current.push(newAtom); | ||
}); | ||
} | ||
useDebugState(storeRef.current, atomsRef.current); | ||
} else { | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues); | ||
} | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues); | ||
} | ||
if (typeof process === "object" && process.env.NODE_ENV !== "production" && isDevStore(storeRef.current)) { | ||
useDebugState(storeRef.current); | ||
} | ||
const StoreContext = getStoreContext(scope); | ||
@@ -607,4 +614,14 @@ return createElement(StoreContext.Provider, {value: storeRef.current}, children); | ||
})); | ||
const getState = (state) => __objSpread({}, state); | ||
const useDebugState = (store, atoms) => { | ||
const isDevStore = (store) => { | ||
return store.length > 2; | ||
}; | ||
const getDevState = (state) => __objSpread({}, state); | ||
const getDevAtoms = ({atoms}) => atoms; | ||
const subscribeDevAtoms = ({listeners}, callback) => { | ||
listeners.add(callback); | ||
return () => listeners.delete(callback); | ||
}; | ||
const useDebugState = (store) => { | ||
const [stateMutableSource, , atomsMutableSource] = store; | ||
const atoms = useMutableSource(atomsMutableSource, getDevAtoms, subscribeDevAtoms); | ||
const subscribe = useCallback((state2, callback) => { | ||
@@ -616,3 +633,3 @@ const unsubs = atoms.map((atom) => subscribeAtom(state2, atom, callback)); | ||
}, [atoms]); | ||
const state = useMutableSource(store[0], getState, subscribe); | ||
const state = useMutableSource(stateMutableSource, getDevState, subscribe); | ||
useDebugValue([state, atoms], stateToPrintable); | ||
@@ -619,0 +636,0 @@ }; |
@@ -10,5 +10,7 @@ export { useUpdateAtom } from './utils/useUpdateAtom'; | ||
export { useAtomCallback } from './utils/useAtomCallback'; | ||
export { freezeAtom, atomFrozenInDev } from './utils/freezeAtom'; | ||
export { freezeAtom, freezeAtomCreator } from './utils/freezeAtom'; | ||
export { splitAtom } from './utils/splitAtom'; | ||
export { atomWithDefault } from './utils/atomWithDefault'; | ||
export { waitForAll } from './utils/waitForAll'; | ||
export { atomWithHash } from './utils/atomWithHash'; | ||
export { atomWithStorage } from './utils/atomWithStorage'; |
@@ -167,2 +167,3 @@ import { useContext, useCallback, useMemo } from 'react'; | ||
const freezeAtomCache = new WeakMap(); | ||
const deepFreeze = (obj) => { | ||
@@ -180,13 +181,20 @@ if (typeof obj !== "object" || obj === null) | ||
function freezeAtom(anAtom) { | ||
const deps = [anAtom]; | ||
const cachedAtom = getWeakCacheItem(freezeAtomCache, deps); | ||
if (cachedAtom) { | ||
return cachedAtom; | ||
} | ||
const frozenAtom = atom((get) => deepFreeze(get(anAtom)), (_get, set, arg) => set(anAtom, arg)); | ||
frozenAtom.scope = anAtom.scope; | ||
setWeakCacheItem(freezeAtomCache, deps, frozenAtom); | ||
return frozenAtom; | ||
} | ||
const atomFrozen = (read, write) => { | ||
const anAtom = atom(read, write); | ||
const origRead = anAtom.read; | ||
anAtom.read = (get) => deepFreeze(origRead(get)); | ||
return anAtom; | ||
}; | ||
const atomFrozenInDev = typeof process === "object" && process.env.NODE_ENV === "development" ? atomFrozen : atom; | ||
function freezeAtomCreator(createAtom) { | ||
return (...params) => { | ||
const anAtom = createAtom(...params); | ||
const origRead = anAtom.read; | ||
anAtom.read = (get) => deepFreeze(origRead(get)); | ||
return anAtom; | ||
}; | ||
} | ||
@@ -338,2 +346,59 @@ const splitAtomCache = new WeakMap(); | ||
export { RESET, atomFamily, atomFrozenInDev, atomWithDefault, atomWithReducer, atomWithReset, freezeAtom, selectAtom, splitAtom, useAtomCallback, useAtomValue, useReducerAtom, useResetAtom, useUpdateAtom, waitForAll }; | ||
function atomWithHash(key, initialValue, serialize = JSON.stringify, deserialize = JSON.parse) { | ||
const anAtom = atom(initialValue, (get, set, update) => { | ||
const newValue = typeof update === "function" ? update(get(anAtom)) : update; | ||
set(anAtom, newValue); | ||
const searchParams = new URLSearchParams(location.hash.slice(1)); | ||
searchParams.set(key, serialize(newValue)); | ||
location.hash = searchParams.toString(); | ||
}); | ||
anAtom.onMount = (setAtom) => { | ||
const callback = () => { | ||
const searchParams = new URLSearchParams(location.hash.slice(1)); | ||
const str = searchParams.get(key); | ||
if (str !== null) { | ||
setAtom(deserialize(str)); | ||
} | ||
}; | ||
window.addEventListener("hashchange", callback); | ||
callback(); | ||
return () => { | ||
window.removeEventListener("hashchange", callback); | ||
}; | ||
}; | ||
return anAtom; | ||
} | ||
const defaultStorage = { | ||
getItem: (key) => { | ||
const storedValue = localStorage.getItem(key); | ||
if (storedValue === null) { | ||
throw new Error("no value stored"); | ||
} | ||
return JSON.parse(storedValue); | ||
}, | ||
setItem: (key, newValue) => { | ||
localStorage.setItem(key, JSON.stringify(newValue)); | ||
} | ||
}; | ||
function atomWithStorage(key, initialValue, storage = defaultStorage) { | ||
const getInitialValue = () => { | ||
try { | ||
return storage.getItem(key); | ||
} catch { | ||
return initialValue; | ||
} | ||
}; | ||
const baseAtom = atom(initialValue); | ||
baseAtom.onMount = (setAtom) => { | ||
Promise.resolve(getInitialValue()).then(setAtom); | ||
}; | ||
const anAtom = atom((get) => get(baseAtom), (get, set, update) => { | ||
const newValue = typeof update === "function" ? update(get(baseAtom)) : update; | ||
set(baseAtom, newValue); | ||
storage.setItem(key, newValue); | ||
}); | ||
return anAtom; | ||
} | ||
export { RESET, atomFamily, atomWithDefault, atomWithHash, atomWithReducer, atomWithReset, atomWithStorage, freezeAtom, freezeAtomCreator, selectAtom, splitAtom, useAtomCallback, useAtomValue, useReducerAtom, useResetAtom, useUpdateAtom, waitForAll }; |
@@ -1,3 +0,3 @@ | ||
import { atom, Atom } from 'jotai'; | ||
export declare function freezeAtom<T extends Atom<any>>(anAtom: T): T; | ||
export declare const atomFrozenInDev: typeof atom; | ||
import { Atom } from 'jotai'; | ||
export declare function freezeAtom<AtomType extends Atom<any>>(anAtom: AtomType): AtomType; | ||
export declare function freezeAtomCreator<CreateAtom extends (...params: any[]) => Atom<any>>(createAtom: CreateAtom): CreateAtom; |
78
index.js
@@ -330,3 +330,2 @@ 'use strict'; | ||
if (errorOrPromise instanceof Promise) { | ||
scheduleReadAtomState(state, atom, errorOrPromise); | ||
promise = errorOrPromise; | ||
@@ -723,5 +722,5 @@ } else if (errorOrPromise instanceof Error) { | ||
var createStore = function createStore(initialValues, newAtomReceiver) { | ||
var state = createState(initialValues, newAtomReceiver); | ||
var mutableSource = createMutableSource(state, function () { | ||
var createStoreForProduction = function createStoreForProduction(initialValues) { | ||
var state = createState(initialValues); | ||
var stateMutableSource = createMutableSource(state, function () { | ||
return state.v; | ||
@@ -734,4 +733,31 @@ }); | ||
return [mutableSource, updateAtom]; | ||
return [stateMutableSource, updateAtom]; | ||
}; | ||
var createStoreForDevelopment = function createStoreForDevelopment(initialValues) { | ||
var atomsStore = { | ||
atoms: [], | ||
listeners: new Set() | ||
}; | ||
var state = createState(initialValues, function (newAtom) { | ||
atomsStore.atoms = [].concat(atomsStore.atoms, [newAtom]); | ||
atomsStore.listeners.forEach(function (listener) { | ||
return listener(); | ||
}); | ||
}); | ||
var stateMutableSource = createMutableSource(state, function () { | ||
return state.v; | ||
}); | ||
var updateAtom = function updateAtom(atom, update) { | ||
return writeAtom(state, atom, update); | ||
}; | ||
var atomsMutableSource = createMutableSource(atomsStore, function () { | ||
return atomsStore.atoms; | ||
}); | ||
return [stateMutableSource, updateAtom, atomsMutableSource]; | ||
}; | ||
var createStore = typeof process === 'object' && process.env.NODE_ENV !== 'production' ? createStoreForDevelopment : createStoreForProduction; | ||
var StoreContextMap = new Map(); | ||
@@ -752,16 +778,8 @@ var getStoreContext = function getStoreContext(scope) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
var atomsRef = react.useRef([]); | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues); | ||
} | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues, function (newAtom) { | ||
atomsRef.current.push(newAtom); | ||
}); | ||
} | ||
useDebugState(storeRef.current, atomsRef.current); | ||
} else { | ||
if (storeRef.current === null) { | ||
storeRef.current = createStore(initialValues); | ||
} | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && isDevStore(storeRef.current)) { | ||
useDebugState(storeRef.current); | ||
} | ||
@@ -798,7 +816,25 @@ | ||
var getState = function getState(state) { | ||
var isDevStore = function isDevStore(store) { | ||
return store.length > 2; | ||
}; | ||
var getDevState = function getDevState(state) { | ||
return _extends({}, state); | ||
}; | ||
var getDevAtoms = function getDevAtoms(_ref3) { | ||
var atoms = _ref3.atoms; | ||
return atoms; | ||
}; | ||
var subscribeDevAtoms = function subscribeDevAtoms(_ref4, callback) { | ||
var listeners = _ref4.listeners; | ||
listeners.add(callback); | ||
return function () { | ||
return listeners.delete(callback); | ||
}; | ||
}; | ||
var useDebugState = function useDebugState(store, atoms) { | ||
var useDebugState = function useDebugState(store) { | ||
var stateMutableSource = store[0], | ||
atomsMutableSource = store[2]; | ||
var atoms = useMutableSource(atomsMutableSource, getDevAtoms, subscribeDevAtoms); | ||
var subscribe = react.useCallback(function (state, callback) { | ||
@@ -814,3 +850,3 @@ var unsubs = atoms.map(function (atom) { | ||
}, [atoms]); | ||
var state = useMutableSource(store[0], getState, subscribe); | ||
var state = useMutableSource(stateMutableSource, getDevState, subscribe); | ||
react.useDebugValue([state, atoms], stateToPrintable); | ||
@@ -817,0 +853,0 @@ }; |
{ | ||
"name": "jotai", | ||
"private": false, | ||
"version": "0.16.3", | ||
"version": "0.16.4", | ||
"description": "👻 Next gen state management that will spook you", | ||
@@ -6,0 +6,0 @@ "main": "index.js", |
@@ -171,8 +171,10 @@ <p align="center"> | ||
- Introduction | ||
- [Concepts](https://docs.pmnd.rs/jotai/concepts) | ||
- [Getting Started](https://docs.pmnd.rs/jotai/getting-started) | ||
- [Async](https://docs.pmnd.rs/jotai/async) | ||
- [Comparison](https://docs.pmnd.rs/jotai/comparison) | ||
- [Showcase](https://docs.pmnd.rs/jotai/showcase) | ||
- Overview | ||
- [Introduction](https://docs.pmnd.rs/jotai/introduction) | ||
- Basics | ||
- [Concepts](https://docs.pmnd.rs/jotai/basics/concepts) | ||
- [Primitives](https://docs.pmnd.rs/jotai/basics/primitives) | ||
- [Async](https://docs.pmnd.rs/jotai/basics/async) | ||
- [Comparison](https://docs.pmnd.rs/jotai/basics/comparison) | ||
- [Showcase](https://docs.pmnd.rs/jotai/basics/showcase) | ||
- Guides | ||
@@ -189,10 +191,10 @@ - [TypeScript](https://docs.pmnd.rs/jotai/guides/typescript) | ||
- [Devtools](https://docs.pmnd.rs/jotai/api/devtools) | ||
- [Immer](https://docs.pmnd.rs/jotai/api/immer) ([immer](https://github.com/immerjs/immer) integration) | ||
- [Optics](https://docs.pmnd.rs/jotai/api/optics) ([optics-ts](https://github.com/akheron/optics-ts) integration) | ||
- [Query](https://docs.pmnd.rs/jotai/api/query) ([react-query](https://github.com/tannerlinsley/react-query) integration) | ||
- [XState](https://docs.pmnd.rs/jotai/api/xstate) ([xstate](https://github.com/davidkpiano/xstate) integration) | ||
- [Valtio](https://docs.pmnd.rs/jotai/api/valtio) ([valtio](https://github.com/pmndrs/valtio) integration) | ||
- [Zustand](https://docs.pmnd.rs/jotai/api/zustand) ([zustand](https://github.com/pmndrs/zustand) integration) | ||
- [Redux](https://docs.pmnd.rs/jotai/api/redux) ([redux](https://github.com/reduxjs/redux) integration) | ||
- [Immer](https://docs.pmnd.rs/jotai/integrations/immer) ([immer](https://github.com/immerjs/immer) integration) | ||
- [Optics](https://docs.pmnd.rs/jotai/integrations/optics) ([optics-ts](https://github.com/akheron/optics-ts) integration) | ||
- [Query](https://docs.pmnd.rs/jotai/integrations/query) ([react-query](https://github.com/tannerlinsley/react-query) integration) | ||
- [XState](https://docs.pmnd.rs/jotai/integrations/xstate) ([xstate](https://github.com/davidkpiano/xstate) integration) | ||
- [Valtio](https://docs.pmnd.rs/jotai/integrations/valtio) ([valtio](https://github.com/pmndrs/valtio) integration) | ||
- [Zustand](https://docs.pmnd.rs/jotai/integrations/zustand) ([zustand](https://github.com/pmndrs/zustand) integration) | ||
- [Redux](https://docs.pmnd.rs/jotai/integrations/redux) ([redux](https://github.com/reduxjs/redux) integration) | ||
- Advanced Recipes | ||
- [Large Objects](https://docs.pmnd.rs/jotai/advanced-recipes/large-objects) |
import { Context } from 'react'; | ||
import { AnyAtom, WritableAtom, Scope } from './types'; | ||
import { NewAtomReceiver } from './vanilla'; | ||
import { State } from './vanilla'; | ||
import { createMutableSource } from './useMutableSource'; | ||
declare type MutableSource = ReturnType<typeof createMutableSource>; | ||
export declare type Store = [ | ||
/*mutableSource*/ MutableSource, | ||
/*updateAtom*/ <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void> | ||
declare type MutableSource<_Target> = ReturnType<typeof createMutableSource>; | ||
declare type UpdateAtom = <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void>; | ||
declare type StoreForProduction = [ | ||
/*stateMutableSource*/ MutableSource<State>, | ||
/*updateAtom*/ UpdateAtom | ||
]; | ||
export declare const createStore: (initialValues?: Iterable<readonly [ | ||
export declare type StoreForDevelopment = [ | ||
/*stateMutableSource*/ MutableSource<State>, | ||
/*updateAtom*/ UpdateAtom, | ||
/*atomsMutableSource*/ MutableSource<{ | ||
atoms: AnyAtom[]; | ||
listeners: Set<() => void>; | ||
}> | ||
]; | ||
export declare type Store = StoreForProduction | StoreForDevelopment; | ||
declare type CreateStore = (initialValues?: Iterable<readonly [ | ||
AnyAtom, | ||
unknown | ||
]> | undefined, newAtomReceiver?: NewAtomReceiver | undefined) => Store; | ||
]>) => Store; | ||
export declare const createStore: CreateStore; | ||
declare type StoreContext = Context<Store>; | ||
export declare const getStoreContext: (scope?: Scope | undefined) => StoreContext; | ||
export {}; |
import React from 'react'; | ||
import { AnyAtom, Scope } from './types'; | ||
import { AtomState, State } from './vanilla'; | ||
export declare const Provider: React.FC<{ | ||
@@ -10,1 +11,18 @@ initialValues?: Iterable<readonly [ | ||
}>; | ||
export declare const getDevState: (state: State) => { | ||
n?: ((newAtom: AnyAtom) => void) | undefined; | ||
v: number; | ||
a: WeakMap<AnyAtom, AtomState<unknown>>; | ||
m: WeakMap<AnyAtom, { | ||
l: Set<() => void>; | ||
d: Set<AnyAtom>; | ||
u: void | import("./types").OnUnmount; | ||
}>; | ||
p: Set<AnyAtom>; | ||
}; | ||
export declare const getDevAtoms: ({ atoms }: { | ||
atoms: AnyAtom[]; | ||
}) => AnyAtom[]; | ||
export declare const subscribeDevAtoms: ({ listeners }: { | ||
listeners: Set<() => void>; | ||
}, callback: () => void) => () => boolean; |
@@ -31,3 +31,3 @@ import { Atom, WritableAtom, AnyAtom, OnUnmount } from './types'; | ||
declare type MountedMap = WeakMap<AnyAtom, Mounted>; | ||
export declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type StateVersion = number; | ||
@@ -34,0 +34,0 @@ declare type PendingAtoms = Set<AnyAtom>; |
export { useAtomDevtools } from './devtools/useAtomDevtools'; | ||
export { useAtomsSnapshot } from './devtools/useAtomsSnapshot'; |
import { Context } from 'react'; | ||
import { AnyAtom, WritableAtom, Scope } from './types'; | ||
import { NewAtomReceiver } from './vanilla'; | ||
import { State } from './vanilla'; | ||
import { createMutableSource } from './useMutableSource'; | ||
declare type MutableSource = ReturnType<typeof createMutableSource>; | ||
export declare type Store = [ | ||
/*mutableSource*/ MutableSource, | ||
/*updateAtom*/ <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void> | ||
declare type MutableSource<_Target> = ReturnType<typeof createMutableSource>; | ||
declare type UpdateAtom = <Value, Update>(atom: WritableAtom<Value, Update>, update: Update) => void | Promise<void>; | ||
declare type StoreForProduction = [ | ||
/*stateMutableSource*/ MutableSource<State>, | ||
/*updateAtom*/ UpdateAtom | ||
]; | ||
export declare const createStore: (initialValues?: Iterable<readonly [ | ||
export declare type StoreForDevelopment = [ | ||
/*stateMutableSource*/ MutableSource<State>, | ||
/*updateAtom*/ UpdateAtom, | ||
/*atomsMutableSource*/ MutableSource<{ | ||
atoms: AnyAtom[]; | ||
listeners: Set<() => void>; | ||
}> | ||
]; | ||
export declare type Store = StoreForProduction | StoreForDevelopment; | ||
declare type CreateStore = (initialValues?: Iterable<readonly [ | ||
AnyAtom, | ||
unknown | ||
]> | undefined, newAtomReceiver?: NewAtomReceiver | undefined) => Store; | ||
]>) => Store; | ||
export declare const createStore: CreateStore; | ||
declare type StoreContext = Context<Store>; | ||
export declare const getStoreContext: (scope?: Scope | undefined) => StoreContext; | ||
export {}; |
import React from 'react'; | ||
import { AnyAtom, Scope } from './types'; | ||
import { AtomState, State } from './vanilla'; | ||
export declare const Provider: React.FC<{ | ||
@@ -10,1 +11,18 @@ initialValues?: Iterable<readonly [ | ||
}>; | ||
export declare const getDevState: (state: State) => { | ||
n?: ((newAtom: AnyAtom) => void) | undefined; | ||
v: number; | ||
a: WeakMap<AnyAtom, AtomState<unknown>>; | ||
m: WeakMap<AnyAtom, { | ||
l: Set<() => void>; | ||
d: Set<AnyAtom>; | ||
u: void | import("./types").OnUnmount; | ||
}>; | ||
p: Set<AnyAtom>; | ||
}; | ||
export declare const getDevAtoms: ({ atoms }: { | ||
atoms: AnyAtom[]; | ||
}) => AnyAtom[]; | ||
export declare const subscribeDevAtoms: ({ listeners }: { | ||
listeners: Set<() => void>; | ||
}, callback: () => void) => () => boolean; |
@@ -31,3 +31,3 @@ import { Atom, WritableAtom, AnyAtom, OnUnmount } from './types'; | ||
declare type MountedMap = WeakMap<AnyAtom, Mounted>; | ||
export declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type NewAtomReceiver = (newAtom: AnyAtom) => void; | ||
declare type StateVersion = number; | ||
@@ -34,0 +34,0 @@ declare type PendingAtoms = Set<AnyAtom>; |
export { useAtomDevtools } from './devtools/useAtomDevtools'; | ||
export { useAtomsSnapshot } from './devtools/useAtomsSnapshot'; |
@@ -10,5 +10,7 @@ export { useUpdateAtom } from './utils/useUpdateAtom'; | ||
export { useAtomCallback } from './utils/useAtomCallback'; | ||
export { freezeAtom, atomFrozenInDev } from './utils/freezeAtom'; | ||
export { freezeAtom, freezeAtomCreator } from './utils/freezeAtom'; | ||
export { splitAtom } from './utils/splitAtom'; | ||
export { atomWithDefault } from './utils/atomWithDefault'; | ||
export { waitForAll } from './utils/waitForAll'; | ||
export { atomWithHash } from './utils/atomWithHash'; | ||
export { atomWithStorage } from './utils/atomWithStorage'; |
@@ -1,3 +0,3 @@ | ||
import { atom, Atom } from 'jotai'; | ||
export declare function freezeAtom<T extends Atom<any>>(anAtom: T): T; | ||
export declare const atomFrozenInDev: typeof atom; | ||
import { Atom } from 'jotai'; | ||
export declare function freezeAtom<AtomType extends Atom<any>>(anAtom: AtomType): AtomType; | ||
export declare function freezeAtomCreator<CreateAtom extends (...params: any[]) => Atom<any>>(createAtom: CreateAtom): CreateAtom; |
@@ -10,5 +10,7 @@ export { useUpdateAtom } from './utils/useUpdateAtom'; | ||
export { useAtomCallback } from './utils/useAtomCallback'; | ||
export { freezeAtom, atomFrozenInDev } from './utils/freezeAtom'; | ||
export { freezeAtom, freezeAtomCreator } from './utils/freezeAtom'; | ||
export { splitAtom } from './utils/splitAtom'; | ||
export { atomWithDefault } from './utils/atomWithDefault'; | ||
export { waitForAll } from './utils/waitForAll'; | ||
export { atomWithHash } from './utils/atomWithHash'; | ||
export { atomWithStorage } from './utils/atomWithStorage'; |
@@ -1,3 +0,3 @@ | ||
import { atom, Atom } from 'jotai'; | ||
export declare function freezeAtom<T extends Atom<any>>(anAtom: T): T; | ||
export declare const atomFrozenInDev: typeof atom; | ||
import { Atom } from 'jotai'; | ||
export declare function freezeAtom<AtomType extends Atom<any>>(anAtom: AtomType): AtomType; | ||
export declare function freezeAtomCreator<CreateAtom extends (...params: any[]) => Atom<any>>(createAtom: CreateAtom): CreateAtom; |
@@ -10,5 +10,7 @@ export { useUpdateAtom } from './utils/useUpdateAtom'; | ||
export { useAtomCallback } from './utils/useAtomCallback'; | ||
export { freezeAtom, atomFrozenInDev } from './utils/freezeAtom'; | ||
export { freezeAtom, freezeAtomCreator } from './utils/freezeAtom'; | ||
export { splitAtom } from './utils/splitAtom'; | ||
export { atomWithDefault } from './utils/atomWithDefault'; | ||
export { waitForAll } from './utils/waitForAll'; | ||
export { atomWithHash } from './utils/atomWithHash'; | ||
export { atomWithStorage } from './utils/atomWithStorage'; |
113
utils.js
@@ -287,2 +287,4 @@ 'use strict'; | ||
var freezeAtomCache = new WeakMap(); | ||
var deepFreeze = function deepFreeze(obj) { | ||
@@ -303,2 +305,9 @@ if (typeof obj !== 'object' || obj === null) return; | ||
function freezeAtom(anAtom) { | ||
var deps = [anAtom]; | ||
var cachedAtom = getWeakCacheItem(freezeAtomCache, deps); | ||
if (cachedAtom) { | ||
return cachedAtom; | ||
} | ||
var frozenAtom = jotai.atom(function (get) { | ||
@@ -310,18 +319,18 @@ return deepFreeze(get(anAtom)); | ||
frozenAtom.scope = anAtom.scope; | ||
setWeakCacheItem(freezeAtomCache, deps, frozenAtom); | ||
return frozenAtom; | ||
} | ||
function freezeAtomCreator(createAtom) { | ||
return function () { | ||
var anAtom = createAtom.apply(void 0, arguments); | ||
var origRead = anAtom.read; | ||
var atomFrozen = function atomFrozen(read, write) { | ||
var anAtom = jotai.atom(read, write); | ||
var origRead = anAtom.read; | ||
anAtom.read = function (get) { | ||
return deepFreeze(origRead(get)); | ||
}; | ||
anAtom.read = function (get) { | ||
return deepFreeze(origRead(get)); | ||
return anAtom; | ||
}; | ||
} | ||
return anAtom; | ||
}; | ||
var atomFrozenInDev = typeof process === 'object' && process.env.NODE_ENV === 'development' ? atomFrozen : jotai.atom; | ||
var splitAtomCache = new WeakMap(); | ||
@@ -508,9 +517,91 @@ | ||
function atomWithHash(key, initialValue, serialize, deserialize) { | ||
if (serialize === void 0) { | ||
serialize = JSON.stringify; | ||
} | ||
if (deserialize === void 0) { | ||
deserialize = JSON.parse; | ||
} | ||
var anAtom = jotai.atom(initialValue, function (get, set, update) { | ||
var newValue = typeof update === 'function' ? update(get(anAtom)) : update; | ||
set(anAtom, newValue); | ||
var searchParams = new URLSearchParams(location.hash.slice(1)); | ||
searchParams.set(key, serialize(newValue)); | ||
location.hash = searchParams.toString(); | ||
}); | ||
anAtom.onMount = function (setAtom) { | ||
var callback = function callback() { | ||
var searchParams = new URLSearchParams(location.hash.slice(1)); | ||
var str = searchParams.get(key); | ||
if (str !== null) { | ||
setAtom(deserialize(str)); | ||
} | ||
}; | ||
window.addEventListener('hashchange', callback); | ||
callback(); | ||
return function () { | ||
window.removeEventListener('hashchange', callback); | ||
}; | ||
}; | ||
return anAtom; | ||
} | ||
var defaultStorage = { | ||
getItem: function getItem(key) { | ||
var storedValue = localStorage.getItem(key); | ||
if (storedValue === null) { | ||
throw new Error('no value stored'); | ||
} | ||
return JSON.parse(storedValue); | ||
}, | ||
setItem: function setItem(key, newValue) { | ||
localStorage.setItem(key, JSON.stringify(newValue)); | ||
} | ||
}; | ||
function atomWithStorage(key, initialValue, storage) { | ||
if (storage === void 0) { | ||
storage = defaultStorage; | ||
} | ||
var getInitialValue = function getInitialValue() { | ||
try { | ||
return storage.getItem(key); | ||
} catch (_unused) { | ||
return initialValue; | ||
} | ||
}; | ||
var baseAtom = jotai.atom(initialValue); | ||
baseAtom.onMount = function (setAtom) { | ||
Promise.resolve(getInitialValue()).then(setAtom); | ||
}; | ||
var anAtom = jotai.atom(function (get) { | ||
return get(baseAtom); | ||
}, function (get, set, update) { | ||
var newValue = typeof update === 'function' ? update(get(baseAtom)) : update; | ||
set(baseAtom, newValue); | ||
storage.setItem(key, newValue); | ||
}); | ||
return anAtom; | ||
} | ||
exports.RESET = RESET; | ||
exports.atomFamily = atomFamily; | ||
exports.atomFrozenInDev = atomFrozenInDev; | ||
exports.atomWithDefault = atomWithDefault; | ||
exports.atomWithHash = atomWithHash; | ||
exports.atomWithReducer = atomWithReducer; | ||
exports.atomWithReset = atomWithReset; | ||
exports.atomWithStorage = atomWithStorage; | ||
exports.freezeAtom = freezeAtom; | ||
exports.freezeAtomCreator = freezeAtomCreator; | ||
exports.selectAtom = selectAtom; | ||
@@ -517,0 +608,0 @@ exports.splitAtom = splitAtom; |
@@ -1,3 +0,3 @@ | ||
import { atom, Atom } from 'jotai'; | ||
export declare function freezeAtom<T extends Atom<any>>(anAtom: T): T; | ||
export declare const atomFrozenInDev: typeof atom; | ||
import { Atom } from 'jotai'; | ||
export declare function freezeAtom<AtomType extends Atom<any>>(anAtom: AtomType): AtomType; | ||
export declare function freezeAtomCreator<CreateAtom extends (...params: any[]) => Atom<any>>(createAtom: CreateAtom): CreateAtom; |
222959
203
5599
199
36