@jayalfredprufrock/mobx-toolbox 0.2.14 → 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/router.d.mts +4 -2
- package/dist/router.d.mts.map +1 -1
- package/dist/router.mjs +5 -5
- package/dist/router.mjs.map +1 -1
- 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/router.d.mts
CHANGED
|
@@ -9,8 +9,8 @@ interface OutletConfig {
|
|
|
9
9
|
loader?: Loader;
|
|
10
10
|
}
|
|
11
11
|
type RouteSegmentState = "preloading" | "loading" | "error" | "ready";
|
|
12
|
+
declare const DefaultOutlet: Component;
|
|
12
13
|
declare class Outlet {
|
|
13
|
-
#private;
|
|
14
14
|
readonly config: OutletConfig;
|
|
15
15
|
state: RouteSegmentState;
|
|
16
16
|
promise: Promise<unknown> | undefined;
|
|
@@ -21,6 +21,8 @@ declare class Outlet {
|
|
|
21
21
|
load(route: Route): Promise<void>;
|
|
22
22
|
setData(data: unknown): void;
|
|
23
23
|
setState(state: RouteSegmentState): void;
|
|
24
|
+
private loadData;
|
|
25
|
+
private loadComponent;
|
|
24
26
|
}
|
|
25
27
|
//#endregion
|
|
26
28
|
//#region src/router/route.d.ts
|
|
@@ -231,5 +233,5 @@ declare const isRedirect: (data: any) => data is Redirector;
|
|
|
231
233
|
declare const isLeaf: (data: any) => data is Leaf;
|
|
232
234
|
declare const isLazyComponent: (data: any) => data is LazyComponent;
|
|
233
235
|
//#endregion
|
|
234
|
-
export { CONTEXT, Component, DynamicRoutePath, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, RouteConfig, RoutePath, Router, RouterOutlet, RouterProps, RouterStore, Routes, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
236
|
+
export { CONTEXT, Component, DefaultOutlet, DynamicRoutePath, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, Outlet, OutletConfig, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, Route, RouteConfig, RoutePath, RouteSegmentState, Router, RouterOutlet, RouterProps, RouterStore, Routes, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
235
237
|
//# sourceMappingURL=router.d.mts.map
|
package/dist/router.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/outlet.tsx","../src/router/route.tsx","../src/router/symbols.ts","../src/router/types.ts","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/router.store.ts","../src/router/components/router.tsx","../src/router/make-routes.tsx","../src/router/redirect.ts","../src/router/util.ts"],"mappings":";;;;;;UAKiB,YAAA;EACf,SAAA,GAAY,SAAA,GAAY,aAAA;EACxB,MAAA,GAAS,MAAA;AAAA;AAAA,KAGC,iBAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/outlet.tsx","../src/router/route.tsx","../src/router/symbols.ts","../src/router/types.ts","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/router.store.ts","../src/router/components/router.tsx","../src/router/make-routes.tsx","../src/router/redirect.ts","../src/router/util.ts"],"mappings":"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"}
|
package/dist/router.mjs
CHANGED
|
@@ -139,8 +139,8 @@ var Outlet = class {
|
|
|
139
139
|
}
|
|
140
140
|
async load(route) {
|
|
141
141
|
const promises = [];
|
|
142
|
-
if (isLazyComponent(this.config.component) && !this.component) promises.push(this
|
|
143
|
-
if (this.config.loader) promises.push(this
|
|
142
|
+
if (isLazyComponent(this.config.component) && !this.component) promises.push(this.loadComponent());
|
|
143
|
+
if (this.config.loader) promises.push(this.loadData(route));
|
|
144
144
|
if (!promises.length) {
|
|
145
145
|
this.setState("ready");
|
|
146
146
|
return;
|
|
@@ -166,10 +166,10 @@ var Outlet = class {
|
|
|
166
166
|
setState(state) {
|
|
167
167
|
this.state = state;
|
|
168
168
|
}
|
|
169
|
-
async
|
|
169
|
+
async loadData(route) {
|
|
170
170
|
await this.config.loader?.(route).then((data) => this.setData(data));
|
|
171
171
|
}
|
|
172
|
-
async
|
|
172
|
+
async loadComponent() {
|
|
173
173
|
if (!isLazyComponent(this.config.component)) return;
|
|
174
174
|
const module = await this.config.component();
|
|
175
175
|
for (const exportName in module) if (exportName === "default" || exportName.endsWith("Page")) {
|
|
@@ -393,5 +393,5 @@ var RouterStore = class {
|
|
|
393
393
|
};
|
|
394
394
|
|
|
395
395
|
//#endregion
|
|
396
|
-
export { CONTEXT, GUARD, LAYOUT, LOAD, Navigate, PAGE, PassThrough, REDIRECT, Redirect, Router, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
396
|
+
export { CONTEXT, DefaultOutlet, GUARD, LAYOUT, LOAD, Navigate, Outlet, PAGE, PassThrough, REDIRECT, Redirect, Route, Router, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
397
397
|
//# sourceMappingURL=router.mjs.map
|
package/dist/router.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.mjs","names":["#loadComponent","#loadData"],"sources":["../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/outlet.tsx","../src/router/redirect.ts","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(0)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}. Paramater '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n if (!store.activeRoute) {\n return null;\n }\n\n const Layout = store.activeRoute.layout ?? PassThrough;\n const components = store.activeRoute.outlets.map((o) => o.Component);\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={store.activeRoute}>\n <RouterOutlet route={store.activeRoute} components={components} />\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \" ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, ...(params as any) } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import { makeAutoObservable, observable } from \"mobx\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.#loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.#loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch(() => {\n clearTimeout(preloadingTimer);\n // TODO: check for type of error\n // handle access denied and redirects\n this.setState(\"error\");\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n async #loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n async #loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { computed, makeObservable } from \"mobx\";\nimport type { Outlet } from \"./outlet\";\nimport type { Component, Guard, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: Guard[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guards = def.guards;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const guard of this.guards) {\n await guard(this);\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, Guard, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: (Guard | undefined)[];\n layout?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n const guards = matchState.guards.filter((g) => g !== undefined);\n\n return new Route({ ...matchState, outlets, guards, path: matchState.segments.join(\"/\") });\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout: routeDef[LAYOUT] ?? matchState?.layout,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [...(matchState?.guards ?? []), routeDef[GUARD]],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER] }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD] }) : undefined,\n ],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith(\"$\"));\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw new Error(\"Not Found.\");\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw new Error(\"Not Found.\");\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n state.guards.push(defAtSegment[GUARD]);\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n }),\n );\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ that aren't at the beginning\n // - path variables must be unique across a path\n\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n const params = {} as Record<string, string>;\n\n const paramSegments = this.activeSegments.filter((segment) => segment.startsWith(\"$\"));\n const pathValues = this.location.pathname.split(\"/\").slice(1);\n\n paramSegments.forEach((segment, index) => {\n const value = pathValues[index + 1];\n if (value) {\n params[segment] = value;\n }\n });\n\n return params as Record<string, string>;\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\"$\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const { to, replace, state, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n const location = {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n\n if (replace) {\n this.history.replace(location, state);\n } else {\n this.history.push(location, state);\n }\n }\n\n setQueryParam(param: string, value: string): void {\n this.search.set(param, value);\n this.history.replace({ search: this.search.toString() });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.toString() });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n this.location = location;\n\n try {\n const matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.mjs","names":[],"sources":["../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/outlet.tsx","../src/router/redirect.ts","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(0)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}. Paramater '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n if (!store.activeRoute) {\n return null;\n }\n\n const Layout = store.activeRoute.layout ?? PassThrough;\n const components = store.activeRoute.outlets.map((o) => o.Component);\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={store.activeRoute}>\n <RouterOutlet route={store.activeRoute} components={components} />\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \" ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, ...(params as any) } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import { makeAutoObservable, observable } from \"mobx\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch(() => {\n clearTimeout(preloadingTimer);\n // TODO: check for type of error\n // handle access denied and redirects\n this.setState(\"error\");\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n private async loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n private async loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { computed, makeObservable } from \"mobx\";\nimport type { Outlet } from \"./outlet\";\nimport type { Component, Guard, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: Guard[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guards = def.guards;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const guard of this.guards) {\n await guard(this);\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, Guard, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: (Guard | undefined)[];\n layout?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n const guards = matchState.guards.filter((g) => g !== undefined);\n\n return new Route({ ...matchState, outlets, guards, path: matchState.segments.join(\"/\") });\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout: routeDef[LAYOUT] ?? matchState?.layout,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [...(matchState?.guards ?? []), routeDef[GUARD]],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER] }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD] }) : undefined,\n ],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith(\"$\"));\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw new Error(\"Not Found.\");\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw new Error(\"Not Found.\");\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n state.guards.push(defAtSegment[GUARD]);\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n }),\n );\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ that aren't at the beginning\n // - path variables must be unique across a path\n\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n const params = {} as Record<string, string>;\n\n const paramSegments = this.activeSegments.filter((segment) => segment.startsWith(\"$\"));\n const pathValues = this.location.pathname.split(\"/\").slice(1);\n\n paramSegments.forEach((segment, index) => {\n const value = pathValues[index + 1];\n if (value) {\n params[segment] = value;\n }\n });\n\n return params as Record<string, string>;\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\"$\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const { to, replace, state, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n const location = {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n\n if (replace) {\n this.history.replace(location, state);\n } else {\n this.history.push(location, state);\n }\n }\n\n setQueryParam(param: string, value: string): void {\n this.search.set(param, value);\n this.history.replace({ search: this.search.toString() });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.toString() });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n this.location = location;\n\n try {\n const matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n throw e;\n }\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",
|