@jayalfredprufrock/mobx-toolbox 0.2.15 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lazy-observable.d.mts +53 -0
- package/dist/lazy-observable.d.mts.map +1 -0
- package/dist/lazy-observable.mjs +127 -0
- package/dist/lazy-observable.mjs.map +1 -0
- package/dist/util.d.mts +2 -33
- package/dist/util.d.mts.map +1 -1
- package/dist/util.mjs +2 -112
- package/dist/util.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IObservableArray } from "mobx";
|
|
3
|
+
|
|
4
|
+
//#region src/lazy-observable/lazy-observable.d.ts
|
|
5
|
+
interface LazyObservable<T = any, TInitialValue = T | undefined> {
|
|
6
|
+
value: TInitialValue;
|
|
7
|
+
reset(): TInitialValue;
|
|
8
|
+
getOrLoad(): Promise<T>;
|
|
9
|
+
set(value: T): void;
|
|
10
|
+
reload(): Promise<T>;
|
|
11
|
+
status: "init" | "loading" | "loaded" | "error";
|
|
12
|
+
loading: boolean;
|
|
13
|
+
loaded: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface LazyObservableOptions {
|
|
16
|
+
shallow?: boolean;
|
|
17
|
+
resetOnUnobserved?: "never" | "always" | number;
|
|
18
|
+
debugName?: string;
|
|
19
|
+
}
|
|
20
|
+
interface LazyObservableOptionsWithInitialValue<TInitialValue> extends LazyObservableOptions {
|
|
21
|
+
initialValue?: TInitialValue;
|
|
22
|
+
}
|
|
23
|
+
declare function lazyObservable<T>(fetch: () => Promise<T>): LazyObservable<T>;
|
|
24
|
+
declare function lazyObservable<T>(fetch: () => Promise<T>, options: LazyObservableOptions): LazyObservable<T>;
|
|
25
|
+
declare function lazyObservable<T, TInitialValue>(fetch: () => Promise<T>, options: LazyObservableOptionsWithInitialValue<TInitialValue>): LazyObservable<T, TInitialValue>;
|
|
26
|
+
interface LazyObservableArray<T = any> extends Omit<LazyObservable<IObservableArray<T>>, "set"> {
|
|
27
|
+
set(value: T[]): void;
|
|
28
|
+
}
|
|
29
|
+
interface LazyObservableArrayOptions<T> extends LazyObservableOptions {
|
|
30
|
+
initialValue?: T[];
|
|
31
|
+
}
|
|
32
|
+
declare function lazyObservableArray<T>(fetch: () => Promise<T[]>, options?: LazyObservableArrayOptions<T>): LazyObservableArray<T>;
|
|
33
|
+
type InferLazyObservable<O> = O extends LazyObservableArray<infer T> ? T[] : O extends LazyObservable<infer T> ? T : never;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/lazy-observable/components/lazy-observer.d.ts
|
|
36
|
+
type LO = LazyObservable | LazyObservableArray;
|
|
37
|
+
type ObserveTuple<O extends LO[]> = { [K in keyof O]: InferLazyObservable<O[K]> };
|
|
38
|
+
interface LazyObserverBaseProps {
|
|
39
|
+
placeholder?: React.ReactNode;
|
|
40
|
+
}
|
|
41
|
+
interface LazyObserverTupleProps<O extends LO[]> extends LazyObserverBaseProps {
|
|
42
|
+
observe: [...O];
|
|
43
|
+
children: (...value: ObserveTuple<O>) => React.ReactNode;
|
|
44
|
+
}
|
|
45
|
+
interface LazyObserverSingleProps<O extends LO> extends LazyObserverBaseProps {
|
|
46
|
+
observe: O;
|
|
47
|
+
children: (value: InferLazyObservable<O>) => React.ReactNode;
|
|
48
|
+
}
|
|
49
|
+
declare function LazyObserver<O extends LO[]>(props: LazyObserverTupleProps<O>): React.ReactNode;
|
|
50
|
+
declare function LazyObserver<O extends LazyObservable>(props: LazyObserverSingleProps<O>): React.ReactNode;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { InferLazyObservable, LazyObservable, LazyObservableArray, LazyObservableArrayOptions, LazyObservableOptions, LazyObservableOptionsWithInitialValue, LazyObserver, LazyObserverBaseProps, LazyObserverSingleProps, LazyObserverTupleProps, lazyObservable, lazyObservableArray };
|
|
53
|
+
//# sourceMappingURL=lazy-observable.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-observable.d.mts","names":[],"sources":["../src/lazy-observable/lazy-observable.ts","../src/lazy-observable/components/lazy-observer.tsx"],"mappings":";;;;UAUiB,cAAA,0BAAwC,CAAA;EACvD,KAAA,EAAO,aAAA;EACP,KAAA,IAAS,aAAA;EACT,SAAA,IAAa,OAAA,CAAQ,CAAA;EACrB,GAAA,CAAI,KAAA,EAAO,CAAA;EACX,MAAA,IAAU,OAAA,CAAQ,CAAA;EAClB,MAAA;EACA,OAAA;EACA,MAAA;AAAA;AAAA,UAGe,qBAAA;EACf,OAAA;EACA,iBAAA;EACA,SAAA;AAAA;AAAA,UAGe,qCAAA,wBAEP,qBAAA;EACR,YAAA,GAAe,aAAA;AAAA;AAAA,iBAGD,cAAA,GAAA,CAAkB,KAAA,QAAa,OAAA,CAAQ,CAAA,IAAK,cAAA,CAAe,CAAA;AAAA,iBAC3D,cAAA,GAAA,CACd,KAAA,QAAa,OAAA,CAAQ,CAAA,GACrB,OAAA,EAAS,qBAAA,GACR,cAAA,CAAe,CAAA;AAAA,iBACF,cAAA,kBAAA,CACd,KAAA,QAAa,OAAA,CAAQ,CAAA,GACrB,OAAA,EAAS,qCAAA,CAAsC,aAAA,IAC9C,cAAA,CAAe,CAAA,EAAG,aAAA;AAAA,UAiJJ,mBAAA,kBAAqC,IAAA,CACpD,cAAA,CAAe,gBAAA,CAAiB,CAAA;EAGhC,GAAA,CAAI,KAAA,EAAO,CAAA;AAAA;AAAA,UAGI,0BAAA,YAAsC,qBAAA;EACrD,YAAA,GAAe,CAAA;AAAA;AAAA,iBAGD,mBAAA,GAAA,CACd,KAAA,QAAa,OAAA,CAAQ,CAAA,KACrB,OAAA,GAAU,0BAAA,CAA2B,CAAA,IACpC,mBAAA,CAAoB,CAAA;AAAA,KAIX,mBAAA,MACV,CAAA,SAAU,mBAAA,YAA+B,CAAA,KAAM,CAAA,SAAU,cAAA,YAA0B,CAAA;;;KCzMhF,EAAA,GAAK,cAAA,GAAiB,mBAAA;AAAA,KAEtB,YAAA,WAAuB,EAAA,oBACd,CAAA,GAAI,mBAAA,CAAoB,CAAA,CAAE,CAAA;AAAA,UAGvB,qBAAA;EACf,WAAA,GAAc,KAAA,CAAM,SAAA;AAAA;AAAA,UAGL,sBAAA,WAAiC,EAAA,YAAc,qBAAA;EAC9D,OAAA,MAAa,CAAA;EACb,QAAA,MAAc,KAAA,EAAO,YAAA,CAAa,CAAA,MAAO,KAAA,CAAM,SAAA;AAAA;AAAA,UAGhC,uBAAA,WAAkC,EAAA,UAAY,qBAAA;EAC7D,OAAA,EAAS,CAAA;EACT,QAAA,GAAW,KAAA,EAAO,mBAAA,CAAoB,CAAA,MAAO,KAAA,CAAM,SAAA;AAAA;AAAA,iBAGrC,YAAA,WAAuB,EAAA,GAAA,CAAM,KAAA,EAAO,sBAAA,CAAuB,CAAA,IAAK,KAAA,CAAM,SAAA;AAAA,iBACtE,YAAA,WAAuB,cAAA,CAAA,CACrC,KAAA,EAAO,uBAAA,CAAwB,CAAA,IAC9B,KAAA,CAAM,SAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Observer } from "mobx-react-lite";
|
|
2
|
+
import { _allowStateChanges, autorun, observable, onBecomeObserved, onBecomeUnobserved } from "mobx";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/lazy-observable/lazy-observable.ts
|
|
6
|
+
function lazyObservable(fetch, options) {
|
|
7
|
+
const value = observable.box(options?.initialValue, { deep: !options?.shallow });
|
|
8
|
+
const status = observable.box("init");
|
|
9
|
+
let resetTimer;
|
|
10
|
+
let autorunDisposer;
|
|
11
|
+
let promise;
|
|
12
|
+
let promiseResolve;
|
|
13
|
+
let promiseReject;
|
|
14
|
+
const getOrCreatePromise = () => {
|
|
15
|
+
if (promise && status.get() !== "loaded" && status.get() !== "error") return promise;
|
|
16
|
+
promise = new Promise((resolve, reject) => {
|
|
17
|
+
promiseResolve = resolve;
|
|
18
|
+
promiseReject = reject;
|
|
19
|
+
});
|
|
20
|
+
return promise;
|
|
21
|
+
};
|
|
22
|
+
const reset = () => {
|
|
23
|
+
clearTimeout(resetTimer);
|
|
24
|
+
autorunDisposer?.();
|
|
25
|
+
_allowStateChanges(true, () => {
|
|
26
|
+
value.set(options?.initialValue);
|
|
27
|
+
status.set("init");
|
|
28
|
+
});
|
|
29
|
+
return options?.initialValue;
|
|
30
|
+
};
|
|
31
|
+
const load = () => {
|
|
32
|
+
if (status.get() === "loading") return;
|
|
33
|
+
clearTimeout(resetTimer);
|
|
34
|
+
autorunDisposer?.();
|
|
35
|
+
autorunDisposer = autorun(() => {
|
|
36
|
+
_allowStateChanges(true, () => {
|
|
37
|
+
status.set("loading");
|
|
38
|
+
});
|
|
39
|
+
fetch().then((newValue) => {
|
|
40
|
+
_allowStateChanges(true, () => {
|
|
41
|
+
value.set(newValue);
|
|
42
|
+
status.set("loaded");
|
|
43
|
+
promiseResolve?.(newValue);
|
|
44
|
+
});
|
|
45
|
+
}).catch((e) => {
|
|
46
|
+
_allowStateChanges(true, () => {
|
|
47
|
+
status.set("error");
|
|
48
|
+
promiseReject?.(e);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const set = (val) => {
|
|
54
|
+
_allowStateChanges(true, () => {
|
|
55
|
+
value.set(val);
|
|
56
|
+
status.set("loaded");
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
let observedCount = 0;
|
|
60
|
+
const onObserved = () => {
|
|
61
|
+
observedCount = Math.min(2, observedCount + 1);
|
|
62
|
+
if (observedCount !== 1) return;
|
|
63
|
+
if (options?.debugName) console.log(`lazyObservable ${options.debugName}`, "observed");
|
|
64
|
+
clearTimeout(resetTimer);
|
|
65
|
+
if (status.get() === "error" || status.get() === "init") load();
|
|
66
|
+
};
|
|
67
|
+
const onUnobserved = () => {
|
|
68
|
+
observedCount = Math.max(0, observedCount - 1);
|
|
69
|
+
if (observedCount) return;
|
|
70
|
+
if (options?.debugName) console.log(`lazyObservable ${options.debugName}`, "unobserved");
|
|
71
|
+
if (options?.resetOnUnobserved === "never") return;
|
|
72
|
+
else if (typeof options?.resetOnUnobserved === "number") resetTimer = setTimeout(() => {
|
|
73
|
+
reset();
|
|
74
|
+
}, options?.resetOnUnobserved);
|
|
75
|
+
else reset();
|
|
76
|
+
};
|
|
77
|
+
onBecomeObserved(value, onObserved);
|
|
78
|
+
onBecomeObserved(status, onObserved);
|
|
79
|
+
onBecomeUnobserved(value, onUnobserved);
|
|
80
|
+
onBecomeUnobserved(status, onUnobserved);
|
|
81
|
+
return {
|
|
82
|
+
get value() {
|
|
83
|
+
return value.get();
|
|
84
|
+
},
|
|
85
|
+
get status() {
|
|
86
|
+
return status.get();
|
|
87
|
+
},
|
|
88
|
+
get loading() {
|
|
89
|
+
return status.get() === "loading";
|
|
90
|
+
},
|
|
91
|
+
get loaded() {
|
|
92
|
+
return status.get() === "loaded";
|
|
93
|
+
},
|
|
94
|
+
reload() {
|
|
95
|
+
const promise = getOrCreatePromise();
|
|
96
|
+
load();
|
|
97
|
+
return promise;
|
|
98
|
+
},
|
|
99
|
+
getOrLoad() {
|
|
100
|
+
if (this.loaded) return Promise.resolve(value.get());
|
|
101
|
+
return this.reload();
|
|
102
|
+
},
|
|
103
|
+
set,
|
|
104
|
+
reset
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function lazyObservableArray(fetch, options) {
|
|
108
|
+
return lazyObservable(fetch, {
|
|
109
|
+
initialValue: [],
|
|
110
|
+
...options
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/lazy-observable/components/lazy-observer.tsx
|
|
116
|
+
function LazyObserver(props) {
|
|
117
|
+
const { observe, placeholder, children } = props;
|
|
118
|
+
const observeAsArray = [observe].flat();
|
|
119
|
+
return /* @__PURE__ */ jsx(Observer, { children: () => {
|
|
120
|
+
if (!observeAsArray.every((o) => o.loaded)) return placeholder;
|
|
121
|
+
return children(...observeAsArray.map((o) => o.value));
|
|
122
|
+
} });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
export { LazyObserver, lazyObservable, lazyObservableArray };
|
|
127
|
+
//# sourceMappingURL=lazy-observable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-observable.mjs","names":[],"sources":["../src/lazy-observable/lazy-observable.ts","../src/lazy-observable/components/lazy-observer.tsx"],"sourcesContent":["import {\n _allowStateChanges,\n autorun,\n type IObservableArray,\n type IReactionDisposer,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n} from \"mobx\";\n\nexport interface LazyObservable<T = any, TInitialValue = T | undefined> {\n value: TInitialValue;\n reset(): TInitialValue;\n getOrLoad(): Promise<T>;\n set(value: T): void;\n reload(): Promise<T>;\n status: \"init\" | \"loading\" | \"loaded\" | \"error\";\n loading: boolean;\n loaded: boolean;\n}\n\nexport interface LazyObservableOptions {\n shallow?: boolean;\n resetOnUnobserved?: \"never\" | \"always\" | number;\n debugName?: string;\n}\n\nexport interface LazyObservableOptionsWithInitialValue<\n TInitialValue,\n> extends LazyObservableOptions {\n initialValue?: TInitialValue;\n}\n\nexport function lazyObservable<T>(fetch: () => Promise<T>): LazyObservable<T>;\nexport function lazyObservable<T>(\n fetch: () => Promise<T>,\n options: LazyObservableOptions,\n): LazyObservable<T>;\nexport function lazyObservable<T, TInitialValue>(\n fetch: () => Promise<T>,\n options: LazyObservableOptionsWithInitialValue<TInitialValue>,\n): LazyObservable<T, TInitialValue>;\n\nexport function lazyObservable<T>(\n fetch: () => Promise<T>,\n options?: LazyObservableOptionsWithInitialValue<T>,\n): LazyObservable<T> {\n const value = observable.box<T>(options?.initialValue, { deep: !options?.shallow });\n const status = observable.box<LazyObservable<T>[\"status\"]>(\"init\");\n\n let resetTimer: NodeJS.Timeout;\n let autorunDisposer: IReactionDisposer;\n\n let promise: Promise<T> | undefined;\n let promiseResolve: ((value: T) => void) | undefined;\n let promiseReject: ((value: unknown) => void) | undefined;\n\n const getOrCreatePromise = () => {\n if (promise && status.get() !== \"loaded\" && status.get() !== \"error\") {\n return promise;\n }\n promise = new Promise<T>((resolve, reject) => {\n promiseResolve = resolve;\n promiseReject = reject;\n });\n return promise;\n };\n\n const reset = () => {\n clearTimeout(resetTimer);\n autorunDisposer?.();\n _allowStateChanges(true, () => {\n value.set(options?.initialValue);\n status.set(\"init\");\n });\n return options?.initialValue;\n };\n\n const load = (): void => {\n if (status.get() === \"loading\") return;\n clearTimeout(resetTimer);\n\n // TODO: this disposer is unreliable while we are using\n // babel to convert all async function to generators\n autorunDisposer?.();\n autorunDisposer = autorun(() => {\n _allowStateChanges(true, () => {\n status.set(\"loading\");\n });\n fetch()\n .then((newValue) => {\n _allowStateChanges(true, () => {\n value.set(newValue);\n status.set(\"loaded\");\n promiseResolve?.(newValue);\n });\n })\n .catch((e) => {\n _allowStateChanges(true, () => {\n status.set(\"error\");\n promiseReject?.(e);\n });\n });\n });\n };\n\n // TODO: should this resolve any promises?\n const set = (val: T): void => {\n _allowStateChanges(true, () => {\n value.set(val);\n status.set(\"loaded\");\n });\n };\n\n let observedCount = 0;\n\n const onObserved = () => {\n observedCount = Math.min(2, observedCount + 1);\n\n // only consider observed the first time this handler gets called\n if (observedCount !== 1) return;\n\n if (options?.debugName) {\n console.log(`lazyObservable ${options.debugName}`, \"observed\");\n }\n clearTimeout(resetTimer);\n if (status.get() === \"error\" || status.get() === \"init\") {\n load();\n }\n };\n\n const onUnobserved = () => {\n observedCount = Math.max(0, observedCount - 1);\n\n // only consider unobserved when count reaches zero\n if (observedCount) return;\n\n if (options?.debugName) {\n console.log(`lazyObservable ${options.debugName}`, \"unobserved\");\n }\n if (options?.resetOnUnobserved === \"never\") {\n return;\n } else if (typeof options?.resetOnUnobserved === \"number\") {\n resetTimer = setTimeout(() => {\n reset();\n }, options?.resetOnUnobserved);\n } else {\n reset();\n }\n };\n\n onBecomeObserved(value, onObserved);\n onBecomeObserved(status, onObserved);\n\n onBecomeUnobserved(value, onUnobserved);\n onBecomeUnobserved(status, onUnobserved);\n\n return {\n get value() {\n return value.get();\n },\n get status() {\n return status.get();\n },\n get loading() {\n return status.get() === \"loading\";\n },\n get loaded() {\n return status.get() === \"loaded\";\n },\n reload() {\n const promise = getOrCreatePromise();\n load();\n return promise;\n },\n getOrLoad() {\n // TODO: this assertion shouldn't be necessary\n // consider fixing box/value type\n if (this.loaded) return Promise.resolve(value.get() as Promise<T>);\n return this.reload();\n },\n set,\n reset,\n };\n}\n\nexport interface LazyObservableArray<T = any> extends Omit<\n LazyObservable<IObservableArray<T>>,\n \"set\"\n> {\n set(value: T[]): void;\n}\n\nexport interface LazyObservableArrayOptions<T> extends LazyObservableOptions {\n initialValue?: T[];\n}\n\nexport function lazyObservableArray<T>(\n fetch: () => Promise<T[]>,\n options?: LazyObservableArrayOptions<T>,\n): LazyObservableArray<T> {\n return lazyObservable(fetch, { initialValue: [], ...options }) as LazyObservableArray<T>;\n}\n\nexport type InferLazyObservable<O> =\n O extends LazyObservableArray<infer T> ? T[] : O extends LazyObservable<infer T> ? T : never;\n","import type { InferLazyObservable, LazyObservable, LazyObservableArray } from \"../lazy-observable\";\nimport { Observer } from \"mobx-react-lite\";\nimport type React from \"react\";\n\ntype LO = LazyObservable | LazyObservableArray;\n\ntype ObserveTuple<O extends LO[]> = {\n [K in keyof O]: InferLazyObservable<O[K]>;\n};\n\nexport interface LazyObserverBaseProps {\n placeholder?: React.ReactNode;\n}\n\nexport interface LazyObserverTupleProps<O extends LO[]> extends LazyObserverBaseProps {\n observe: [...O];\n children: (...value: ObserveTuple<O>) => React.ReactNode;\n}\n\nexport interface LazyObserverSingleProps<O extends LO> extends LazyObserverBaseProps {\n observe: O;\n children: (value: InferLazyObservable<O>) => React.ReactNode;\n}\n\nexport function LazyObserver<O extends LO[]>(props: LazyObserverTupleProps<O>): React.ReactNode;\nexport function LazyObserver<O extends LazyObservable>(\n props: LazyObserverSingleProps<O>,\n): React.ReactNode;\nexport function LazyObserver(\n props: LazyObserverTupleProps<any> | LazyObserverSingleProps<any>,\n): React.ReactNode {\n const { observe, placeholder, children } = props;\n const observeAsArray = [observe].flat() as LO[];\n return (\n <Observer>\n {() => {\n if (!observeAsArray.every((o) => o.loaded)) return placeholder;\n return (children as any)(...observeAsArray.map((o) => o.value));\n }}\n </Observer>\n );\n}\n"],"mappings":"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"}
|
package/dist/util.d.mts
CHANGED
|
@@ -1,42 +1,11 @@
|
|
|
1
|
-
import { IAutorunOptions,
|
|
1
|
+
import { IAutorunOptions, IReactionPublic } from "mobx";
|
|
2
2
|
import { ClassAccessorDecorator } from "mobx/dist/types/decorator_fills";
|
|
3
3
|
|
|
4
|
-
//#region src/util/lazy-observable.d.ts
|
|
5
|
-
interface LazyObservable<T = any, TInitialValue = T | undefined> {
|
|
6
|
-
value: TInitialValue;
|
|
7
|
-
reset(): TInitialValue;
|
|
8
|
-
getOrLoad(): Promise<T>;
|
|
9
|
-
set(value: T): void;
|
|
10
|
-
reload(): Promise<T>;
|
|
11
|
-
status: "init" | "loading" | "loaded" | "error";
|
|
12
|
-
loading: boolean;
|
|
13
|
-
loaded: boolean;
|
|
14
|
-
}
|
|
15
|
-
interface LazyObservableOptions {
|
|
16
|
-
shallow?: boolean;
|
|
17
|
-
resetOnUnobserved?: "never" | "always" | number;
|
|
18
|
-
debugName?: string;
|
|
19
|
-
}
|
|
20
|
-
interface LazyObservableOptionsWithInitialValue<TInitialValue> extends LazyObservableOptions {
|
|
21
|
-
initialValue?: TInitialValue;
|
|
22
|
-
}
|
|
23
|
-
declare function lazyObservable<T>(fetch: () => Promise<T>): LazyObservable<T>;
|
|
24
|
-
declare function lazyObservable<T>(fetch: () => Promise<T>, options: LazyObservableOptions): LazyObservable<T>;
|
|
25
|
-
declare function lazyObservable<T, TInitialValue>(fetch: () => Promise<T>, options: LazyObservableOptionsWithInitialValue<TInitialValue>): LazyObservable<T, TInitialValue>;
|
|
26
|
-
interface LazyObservableArray<T> extends Omit<LazyObservable<IObservableArray<T>>, "set"> {
|
|
27
|
-
set(value: T[]): void;
|
|
28
|
-
}
|
|
29
|
-
interface LazyObservableArrayOptions<T> extends LazyObservableOptions {
|
|
30
|
-
initialValue?: T[];
|
|
31
|
-
}
|
|
32
|
-
declare function lazyObservableArray<T>(fetch: () => Promise<T[]>, options?: LazyObservableArrayOptions<T>): LazyObservableArray<T>;
|
|
33
|
-
type InferLazyObservable<O> = O extends LazyObservableArray<infer T> ? T[] : O extends LazyObservable<infer T> ? T : never;
|
|
34
|
-
//#endregion
|
|
35
4
|
//#region src/util/mutable.d.ts
|
|
36
5
|
declare const mutable: ClassAccessorDecorator;
|
|
37
6
|
//#endregion
|
|
38
7
|
//#region src/util/use-autorun.d.ts
|
|
39
8
|
declare function useAutorun(func: (r: IReactionPublic) => unknown, options?: IAutorunOptions): void;
|
|
40
9
|
//#endregion
|
|
41
|
-
export {
|
|
10
|
+
export { mutable, useAutorun };
|
|
42
11
|
//# sourceMappingURL=util.d.mts.map
|
package/dist/util.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.mts","names":[],"sources":["../src/util/
|
|
1
|
+
{"version":3,"file":"util.d.mts","names":[],"sources":["../src/util/mutable.ts","../src/util/use-autorun.ts"],"mappings":";;;;cAGa,OAAA,EAAS,sBAAA;;;iBCAN,UAAA,CAAW,IAAA,GAAO,CAAA,EAAG,eAAA,cAA6B,OAAA,GAAU,eAAA"}
|
package/dist/util.mjs
CHANGED
|
@@ -1,116 +1,6 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { autorun, observable, runInAction } from "mobx";
|
|
3
3
|
|
|
4
|
-
//#region src/util/lazy-observable.ts
|
|
5
|
-
function lazyObservable(fetch, options) {
|
|
6
|
-
const value = observable.box(options?.initialValue, { deep: !options?.shallow });
|
|
7
|
-
const status = observable.box("init");
|
|
8
|
-
let resetTimer;
|
|
9
|
-
let autorunDisposer;
|
|
10
|
-
let promise;
|
|
11
|
-
let promiseResolve;
|
|
12
|
-
let promiseReject;
|
|
13
|
-
const getOrCreatePromise = () => {
|
|
14
|
-
if (promise && status.get() !== "loaded" && status.get() !== "error") return promise;
|
|
15
|
-
promise = new Promise((resolve, reject) => {
|
|
16
|
-
promiseResolve = resolve;
|
|
17
|
-
promiseReject = reject;
|
|
18
|
-
});
|
|
19
|
-
return promise;
|
|
20
|
-
};
|
|
21
|
-
const reset = () => {
|
|
22
|
-
clearTimeout(resetTimer);
|
|
23
|
-
autorunDisposer?.();
|
|
24
|
-
_allowStateChanges(true, () => {
|
|
25
|
-
value.set(options?.initialValue);
|
|
26
|
-
status.set("init");
|
|
27
|
-
});
|
|
28
|
-
return options?.initialValue;
|
|
29
|
-
};
|
|
30
|
-
const load = () => {
|
|
31
|
-
if (status.get() === "loading") return;
|
|
32
|
-
clearTimeout(resetTimer);
|
|
33
|
-
autorunDisposer?.();
|
|
34
|
-
autorunDisposer = autorun(() => {
|
|
35
|
-
_allowStateChanges(true, () => {
|
|
36
|
-
status.set("loading");
|
|
37
|
-
});
|
|
38
|
-
fetch().then((newValue) => {
|
|
39
|
-
_allowStateChanges(true, () => {
|
|
40
|
-
value.set(newValue);
|
|
41
|
-
status.set("loaded");
|
|
42
|
-
promiseResolve?.(newValue);
|
|
43
|
-
});
|
|
44
|
-
}).catch((e) => {
|
|
45
|
-
_allowStateChanges(true, () => {
|
|
46
|
-
status.set("error");
|
|
47
|
-
promiseReject?.(e);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
const set = (val) => {
|
|
53
|
-
_allowStateChanges(true, () => {
|
|
54
|
-
value.set(val);
|
|
55
|
-
status.set("loaded");
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
let observedCount = 0;
|
|
59
|
-
const onObserved = () => {
|
|
60
|
-
observedCount = Math.min(2, observedCount + 1);
|
|
61
|
-
if (observedCount !== 1) return;
|
|
62
|
-
if (options?.debugName) console.log(`lazyObservable ${options.debugName}`, "observed");
|
|
63
|
-
clearTimeout(resetTimer);
|
|
64
|
-
if (status.get() === "error" || status.get() === "init") load();
|
|
65
|
-
};
|
|
66
|
-
const onUnobserved = () => {
|
|
67
|
-
observedCount = Math.max(0, observedCount - 1);
|
|
68
|
-
if (observedCount) return;
|
|
69
|
-
if (options?.debugName) console.log(`lazyObservable ${options.debugName}`, "unobserved");
|
|
70
|
-
if (options?.resetOnUnobserved === "never") return;
|
|
71
|
-
else if (typeof options?.resetOnUnobserved === "number") resetTimer = setTimeout(() => {
|
|
72
|
-
reset();
|
|
73
|
-
}, options?.resetOnUnobserved);
|
|
74
|
-
else reset();
|
|
75
|
-
};
|
|
76
|
-
onBecomeObserved(value, onObserved);
|
|
77
|
-
onBecomeObserved(status, onObserved);
|
|
78
|
-
onBecomeUnobserved(value, onUnobserved);
|
|
79
|
-
onBecomeUnobserved(status, onUnobserved);
|
|
80
|
-
return {
|
|
81
|
-
get value() {
|
|
82
|
-
return value.get();
|
|
83
|
-
},
|
|
84
|
-
get status() {
|
|
85
|
-
return status.get();
|
|
86
|
-
},
|
|
87
|
-
get loading() {
|
|
88
|
-
return status.get() === "loading";
|
|
89
|
-
},
|
|
90
|
-
get loaded() {
|
|
91
|
-
return status.get() === "loaded";
|
|
92
|
-
},
|
|
93
|
-
reload() {
|
|
94
|
-
const promise = getOrCreatePromise();
|
|
95
|
-
load();
|
|
96
|
-
return promise;
|
|
97
|
-
},
|
|
98
|
-
getOrLoad() {
|
|
99
|
-
if (this.loaded) return Promise.resolve(value.get());
|
|
100
|
-
return this.reload();
|
|
101
|
-
},
|
|
102
|
-
set,
|
|
103
|
-
reset
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function lazyObservableArray(fetch, options) {
|
|
107
|
-
return lazyObservable(fetch, {
|
|
108
|
-
initialValue: [],
|
|
109
|
-
...options
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
//#endregion
|
|
114
4
|
//#region src/util/mutable.ts
|
|
115
5
|
const mutable = (accessor) => {
|
|
116
6
|
const boxedValues = /* @__PURE__ */ new WeakMap();
|
|
@@ -142,5 +32,5 @@ function useAutorun(func, options) {
|
|
|
142
32
|
}
|
|
143
33
|
|
|
144
34
|
//#endregion
|
|
145
|
-
export {
|
|
35
|
+
export { mutable, useAutorun };
|
|
146
36
|
//# sourceMappingURL=util.mjs.map
|
package/dist/util.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.mjs","names":[],"sources":["../src/util/
|
|
1
|
+
{"version":3,"file":"util.mjs","names":[],"sources":["../src/util/mutable.ts","../src/util/use-autorun.ts"],"sourcesContent":["import { observable, runInAction } from \"mobx\";\nimport type { ClassAccessorDecorator } from \"mobx/dist/types/decorator_fills\";\n\nexport const mutable: ClassAccessorDecorator = (accessor) => {\n const boxedValues = new WeakMap();\n\n return {\n get() {\n let boxedValue = boxedValues.get(this);\n if (!boxedValue) {\n const value = accessor.get.call(this);\n boxedValue = observable.box(value);\n boxedValues.set(this, boxedValue);\n }\n\n return boxedValue.get();\n },\n set(value) {\n let boxedValue = boxedValues.get(this);\n if (!boxedValue) {\n boxedValue = observable.box(value);\n boxedValues.set(this, boxedValue);\n }\n\n runInAction(() => boxedValue.set(value));\n },\n };\n};\n","import { autorun, type IAutorunOptions, type IReactionPublic } from \"mobx\";\nimport { useEffect } from \"react\";\n\nexport function useAutorun(func: (r: IReactionPublic) => unknown, options?: IAutorunOptions): void {\n // biome-ignore lint/correctness/useExhaustiveDependencies: by design\n useEffect(() => autorun(func, options), []);\n}\n"],"mappings":";;;;AAGA,MAAa,WAAmC,aAAa;CAC3D,MAAM,8BAAc,IAAI,SAAS;AAEjC,QAAO;EACL,MAAM;GACJ,IAAI,aAAa,YAAY,IAAI,KAAK;AACtC,OAAI,CAAC,YAAY;IACf,MAAM,QAAQ,SAAS,IAAI,KAAK,KAAK;AACrC,iBAAa,WAAW,IAAI,MAAM;AAClC,gBAAY,IAAI,MAAM,WAAW;;AAGnC,UAAO,WAAW,KAAK;;EAEzB,IAAI,OAAO;GACT,IAAI,aAAa,YAAY,IAAI,KAAK;AACtC,OAAI,CAAC,YAAY;AACf,iBAAa,WAAW,IAAI,MAAM;AAClC,gBAAY,IAAI,MAAM,WAAW;;AAGnC,qBAAkB,WAAW,IAAI,MAAM,CAAC;;EAE3C;;;;;ACvBH,SAAgB,WAAW,MAAuC,SAAiC;AAEjG,iBAAgB,QAAQ,MAAM,QAAQ,EAAE,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jayalfredprufrock/mobx-toolbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Misc mobx/react modules/utilities.",
|
|
5
5
|
"homepage": "https://github.com/jayalfredprufrock/mobx-toolbox#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
"./dialog": "./dist/dialog.mjs",
|
|
20
20
|
"./form": "./dist/form.mjs",
|
|
21
|
+
"./lazy-observable": "./dist/lazy-observable.mjs",
|
|
21
22
|
"./react-util": "./dist/react-util.mjs",
|
|
22
23
|
"./router": "./dist/router.mjs",
|
|
23
24
|
"./util": "./dist/util.mjs",
|