jotai
Version:
👻 Next gen state management that will spook you
584 lines (569 loc) • 20.8 kB
JavaScript
System.register(['jotai/vanilla'], (function (exports) {
'use strict';
var atom;
return {
setters: [function (module) {
atom = module.atom;
}],
execute: (function () {
exports({
atomFamily: atomFamily,
atomWithDefault: atomWithDefault,
atomWithObservable: atomWithObservable,
atomWithReducer: atomWithReducer,
atomWithReset: atomWithReset,
atomWithStorage: atomWithStorage,
createJSONStorage: createJSONStorage,
freezeAtom: freezeAtom,
freezeAtomCreator: freezeAtomCreator,
loadable: loadable,
selectAtom: selectAtom,
splitAtom: splitAtom,
unstable_unwrap: unwrap
});
const RESET = exports('RESET', Symbol());
function atomWithReset(initialValue) {
const anAtom = atom(
initialValue,
(get, set, update) => {
const nextValue = typeof update === "function" ? update(get(anAtom)) : update;
set(anAtom, nextValue === RESET ? initialValue : nextValue);
}
);
return anAtom;
}
function atomWithReducer(initialValue, reducer) {
const anAtom = atom(
initialValue,
(get, set, action) => set(anAtom, reducer(get(anAtom), action))
);
return anAtom;
}
function atomFamily(initializeAtom, areEqual) {
let shouldRemove = null;
const atoms = /* @__PURE__ */ new Map();
const createAtom = (param) => {
let item;
if (areEqual === void 0) {
item = atoms.get(param);
} else {
for (const [key, value] of atoms) {
if (areEqual(key, param)) {
item = value;
break;
}
}
}
if (item !== void 0) {
if (shouldRemove == null ? void 0 : shouldRemove(item[1], param)) {
createAtom.remove(param);
} else {
return item[0];
}
}
const newAtom = initializeAtom(param);
atoms.set(param, [newAtom, Date.now()]);
return newAtom;
};
createAtom.remove = (param) => {
if (areEqual === void 0) {
atoms.delete(param);
} else {
for (const [key] of atoms) {
if (areEqual(key, param)) {
atoms.delete(key);
break;
}
}
}
};
createAtom.setShouldRemove = (fn) => {
shouldRemove = fn;
if (!shouldRemove)
return;
for (const [key, value] of atoms) {
if (shouldRemove(value[1], key)) {
atoms.delete(key);
}
}
};
return createAtom;
}
const getCached$1 = (c, m, k) => (m.has(k) ? m : m.set(k, c())).get(k);
const cache1$4 = /* @__PURE__ */ new WeakMap();
const memo3 = (create, dep1, dep2, dep3) => {
const cache2 = getCached$1(() => /* @__PURE__ */ new WeakMap(), cache1$4, dep1);
const cache3 = getCached$1(() => /* @__PURE__ */ new WeakMap(), cache2, dep2);
return getCached$1(create, cache3, dep3);
};
function selectAtom(anAtom, selector, equalityFn = Object.is) {
return memo3(
() => {
const refAtom = atom(() => ({}));
const derivedAtom = atom((get) => {
const ref = get(refAtom);
const selectValue = (value2) => {
const slice = selector(value2);
if ("prev" in ref && equalityFn(ref.prev, slice)) {
return ref.prev;
}
return ref.prev = slice;
};
const value = get(anAtom);
if (value instanceof Promise) {
return value.then(selectValue);
}
return selectValue(value);
});
return derivedAtom;
},
anAtom,
selector,
equalityFn
);
}
const cache1$3 = /* @__PURE__ */ new WeakMap();
const memo1$2 = (create, dep1) => (cache1$3.has(dep1) ? cache1$3 : cache1$3.set(dep1, create())).get(dep1);
const deepFreeze = (obj) => {
if (typeof obj !== "object" || obj === null)
return;
Object.freeze(obj);
const propNames = Object.getOwnPropertyNames(obj);
for (const name of propNames) {
const value = obj[name];
deepFreeze(value);
}
return obj;
};
function freezeAtom(anAtom) {
return memo1$2(() => {
const frozenAtom = atom(
(get) => deepFreeze(get(anAtom)),
(_get, set, arg) => set(anAtom, arg)
);
return frozenAtom;
}, anAtom);
}
function freezeAtomCreator(createAtom) {
return (...params) => {
const anAtom = createAtom(...params);
const origRead = anAtom.read;
anAtom.read = (get, options) => deepFreeze(origRead(get, options));
return anAtom;
};
}
const getCached = (c, m, k) => (m.has(k) ? m : m.set(k, c())).get(k);
const cache1$2 = /* @__PURE__ */ new WeakMap();
const memo2 = (create, dep1, dep2) => {
const cache2 = getCached(() => /* @__PURE__ */ new WeakMap(), cache1$2, dep1);
return getCached(create, cache2, dep2);
};
const cacheKeyForEmptyKeyExtractor = {};
const isWritable = (atom2) => !!atom2.write;
const isFunction = (x) => typeof x === "function";
function splitAtom(arrAtom, keyExtractor) {
return memo2(
() => {
const mappingCache = /* @__PURE__ */ new WeakMap();
const getMapping = (arr, prev) => {
let mapping = mappingCache.get(arr);
if (mapping) {
return mapping;
}
const prevMapping = prev && mappingCache.get(prev);
const atomList = [];
const keyList = [];
arr.forEach((item, index) => {
const key = keyExtractor ? keyExtractor(item) : index;
keyList[index] = key;
const cachedAtom = prevMapping && prevMapping.atomList[prevMapping.keyList.indexOf(key)];
if (cachedAtom) {
atomList[index] = cachedAtom;
return;
}
const read2 = (get) => {
const ref = get(refAtom);
const currArr = get(arrAtom);
const mapping2 = getMapping(currArr, ref.prev);
const index2 = mapping2.keyList.indexOf(key);
if (index2 < 0 || index2 >= currArr.length) {
const prevItem = arr[getMapping(arr).keyList.indexOf(key)];
if (prevItem) {
return prevItem;
}
throw new Error("splitAtom: index out of bounds for read");
}
return currArr[index2];
};
const write2 = (get, set, update) => {
const ref = get(refAtom);
const arr2 = get(arrAtom);
const mapping2 = getMapping(arr2, ref.prev);
const index2 = mapping2.keyList.indexOf(key);
if (index2 < 0 || index2 >= arr2.length) {
throw new Error("splitAtom: index out of bounds for write");
}
const nextItem = isFunction(update) ? update(arr2[index2]) : update;
set(arrAtom, [
...arr2.slice(0, index2),
nextItem,
...arr2.slice(index2 + 1)
]);
};
atomList[index] = isWritable(arrAtom) ? atom(read2, write2) : atom(read2);
});
if (prevMapping && prevMapping.keyList.length === keyList.length && prevMapping.keyList.every((x, i) => x === keyList[i])) {
mapping = prevMapping;
} else {
mapping = { atomList, keyList };
}
mappingCache.set(arr, mapping);
return mapping;
};
const refAtom = atom(() => ({}));
const read = (get) => {
const ref = get(refAtom);
const arr = get(arrAtom);
const mapping = getMapping(arr, ref.prev);
ref.prev = arr;
return mapping.atomList;
};
const write = (get, set, action) => {
switch (action.type) {
case "remove": {
const index = get(splittedAtom).indexOf(action.atom);
if (index >= 0) {
const arr = get(arrAtom);
set(arrAtom, [
...arr.slice(0, index),
...arr.slice(index + 1)
]);
}
break;
}
case "insert": {
const index = action.before ? get(splittedAtom).indexOf(action.before) : get(splittedAtom).length;
if (index >= 0) {
const arr = get(arrAtom);
set(arrAtom, [
...arr.slice(0, index),
action.value,
...arr.slice(index)
]);
}
break;
}
case "move": {
const index1 = get(splittedAtom).indexOf(action.atom);
const index2 = action.before ? get(splittedAtom).indexOf(action.before) : get(splittedAtom).length;
if (index1 >= 0 && index2 >= 0) {
const arr = get(arrAtom);
if (index1 < index2) {
set(arrAtom, [
...arr.slice(0, index1),
...arr.slice(index1 + 1, index2),
arr[index1],
...arr.slice(index2)
]);
} else {
set(arrAtom, [
...arr.slice(0, index2),
arr[index1],
...arr.slice(index2, index1),
...arr.slice(index1 + 1)
]);
}
}
break;
}
}
};
const splittedAtom = isWritable(arrAtom) ? atom(read, write) : atom(read);
return splittedAtom;
},
arrAtom,
keyExtractor || cacheKeyForEmptyKeyExtractor
);
}
const updateValue = (prevValue, update) => typeof update === "function" ? update(prevValue) : update;
function atomWithDefault(getDefault) {
const EMPTY = Symbol();
const overwrittenAtom = atom(EMPTY);
const anAtom = atom(
(get, options) => {
const overwritten = get(overwrittenAtom);
if (overwritten !== EMPTY) {
return overwritten;
}
return getDefault(get, options);
},
(get, set, update) => {
if (update === RESET) {
return set(overwrittenAtom, EMPTY);
}
const prevValue = get(anAtom);
if (prevValue instanceof Promise) {
return prevValue.then(
(v) => set(overwrittenAtom, updateValue(v, update))
);
}
return set(
overwrittenAtom,
updateValue(prevValue, update)
);
}
);
return anAtom;
}
const NO_STORAGE_VALUE = exports('unstable_NO_STORAGE_VALUE', Symbol());
function createJSONStorage(getStringStorage) {
let lastStr;
let lastValue;
const storage = {
getItem: (key) => {
var _a, _b;
const parse = (str2) => {
str2 = str2 || "";
if (lastStr !== str2) {
try {
lastValue = JSON.parse(str2);
} catch {
return NO_STORAGE_VALUE;
}
lastStr = str2;
}
return lastValue;
};
const str = (_b = (_a = getStringStorage()) == null ? void 0 : _a.getItem(key)) != null ? _b : null;
if (str instanceof Promise) {
return str.then(parse);
}
return parse(str);
},
setItem: (key, newValue) => {
var _a;
return (_a = getStringStorage()) == null ? void 0 : _a.setItem(key, JSON.stringify(newValue));
},
removeItem: (key) => {
var _a;
return (_a = getStringStorage()) == null ? void 0 : _a.removeItem(key);
}
};
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
storage.subscribe = (key, callback) => {
const storageEventCallback = (e) => {
if (e.key === key && e.newValue) {
callback(JSON.parse(e.newValue));
}
};
window.addEventListener("storage", storageEventCallback);
return () => {
window.removeEventListener("storage", storageEventCallback);
};
};
}
return storage;
}
const defaultStorage = createJSONStorage(
() => typeof window !== "undefined" ? window.localStorage : void 0
);
function atomWithStorage(key, initialValue, storage = defaultStorage) {
const baseAtom = atom(initialValue);
baseAtom.onMount = (setAtom) => {
const value = storage.getItem(key);
if (value instanceof Promise) {
value.then((v) => setAtom(v === NO_STORAGE_VALUE ? initialValue : v));
} else {
setAtom(value === NO_STORAGE_VALUE ? initialValue : value);
}
let unsub;
if (storage.subscribe) {
unsub = storage.subscribe(key, setAtom);
}
return unsub;
};
const anAtom = atom(
(get) => get(baseAtom),
(get, set, update) => {
const nextValue = typeof update === "function" ? update(get(baseAtom)) : update;
if (nextValue === RESET) {
set(baseAtom, initialValue);
return storage.removeItem(key);
}
set(baseAtom, nextValue);
return storage.setItem(key, nextValue);
}
);
return anAtom;
}
function atomWithObservable(getObservable, options) {
const returnResultData = (result) => {
if ("e" in result) {
throw result.e;
}
return result.d;
};
const observableResultAtom = atom((get) => {
var _a;
let observable = getObservable(get);
const itself = (_a = observable[Symbol.observable]) == null ? void 0 : _a.call(observable);
if (itself) {
observable = itself;
}
let resolve;
const makePending = () => new Promise((r) => {
resolve = r;
});
const initialResult = options && "initialValue" in options ? {
d: typeof options.initialValue === "function" ? options.initialValue() : options.initialValue
} : makePending();
let setResult;
let lastResult;
const listener = (result) => {
lastResult = result;
resolve == null ? void 0 : resolve(result);
setResult == null ? void 0 : setResult(result);
};
let subscription;
let timer;
const isNotMounted = () => !setResult;
const start = () => {
if (subscription) {
clearTimeout(timer);
subscription.unsubscribe();
}
subscription = observable.subscribe({
next: (d) => listener({ d }),
error: (e) => listener({ e }),
complete: () => {
}
});
if (isNotMounted() && (options == null ? void 0 : options.unstable_timeout)) {
timer = setTimeout(() => {
if (subscription) {
subscription.unsubscribe();
subscription = void 0;
}
}, options.unstable_timeout);
}
};
start();
const resultAtom = atom(lastResult || initialResult);
resultAtom.onMount = (update) => {
setResult = update;
if (lastResult) {
update(lastResult);
}
if (subscription) {
clearTimeout(timer);
} else {
start();
}
return () => {
setResult = void 0;
if (subscription) {
subscription.unsubscribe();
subscription = void 0;
}
};
};
return [resultAtom, observable, makePending, start, isNotMounted];
});
const observableAtom = atom(
(get) => {
const [resultAtom] = get(observableResultAtom);
const result = get(resultAtom);
if (result instanceof Promise) {
return result.then(returnResultData);
}
return returnResultData(result);
},
(get, set, data) => {
const [resultAtom, observable, makePending, start, isNotMounted] = get(observableResultAtom);
if ("next" in observable) {
if (isNotMounted()) {
set(resultAtom, makePending());
start();
}
observable.next(data);
} else {
throw new Error("observable is not subject");
}
}
);
return observableAtom;
}
const cache1$1 = /* @__PURE__ */ new WeakMap();
const memo1$1 = (create, dep1) => (cache1$1.has(dep1) ? cache1$1 : cache1$1.set(dep1, create())).get(dep1);
const LOADING = { state: "loading" };
function loadable(anAtom) {
return memo1$1(() => {
const loadableCache = /* @__PURE__ */ new WeakMap();
const refreshAtom = atom(0);
const derivedAtom = atom(
(get, { setSelf }) => {
get(refreshAtom);
const promise = get(anAtom);
if (!(promise instanceof Promise)) {
return { state: "hasData", data: promise };
}
const cached = loadableCache.get(promise);
if (cached) {
return cached;
}
loadableCache.set(promise, LOADING);
promise.then(
(data) => {
loadableCache.set(promise, { state: "hasData", data });
},
(error) => {
loadableCache.set(promise, { state: "hasError", error });
}
).finally(setSelf);
return LOADING;
},
(_get, set) => {
set(refreshAtom, (c) => c + 1);
}
);
return atom((get) => get(derivedAtom));
}, anAtom);
}
const cache1 = /* @__PURE__ */ new WeakMap();
const memo1 = (create, dep1) => (cache1.has(dep1) ? cache1 : cache1.set(dep1, create())).get(dep1);
function unwrap(anAtom, defaultValue) {
return memo1(() => {
const refAtom = atom(
() => ({})
);
const refreshAtom = atom(0);
const derivedAtom = atom(
(get, { setSelf }) => {
get(refreshAtom);
const ref = get(refAtom);
const promise = get(anAtom);
if (ref.p !== promise) {
promise.then(
(v) => ref.v = v,
(e) => ref.e = e
).finally(setSelf);
ref.p = promise;
}
if ("e" in ref) {
throw ref.e;
}
if ("v" in ref) {
return ref.v;
}
return defaultValue;
},
(_get, set) => {
set(refreshAtom, (c) => c + 1);
}
);
return atom((get) => get(derivedAtom));
}, anAtom);
}
})
};
}));