mobx-mantle 0.3.6 → 0.6.1
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/README.md +897 -154
- package/dist/behaviors/index.cjs +419 -0
- package/dist/behaviors/index.cjs.map +1 -0
- package/dist/behaviors/index.d.cts +275 -0
- package/dist/behaviors/index.d.ts +275 -0
- package/dist/behaviors/index.js +419 -0
- package/dist/behaviors/index.js.map +1 -0
- package/dist/chunk-LP5TAGSI.js +9 -0
- package/dist/chunk-LP5TAGSI.js.map +1 -0
- package/dist/chunk-WNF647U6.cjs +9 -0
- package/dist/chunk-WNF647U6.cjs.map +1 -0
- package/dist/index.cjs +1172 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +431 -83
- package/dist/index.d.ts +431 -83
- package/dist/index.js +1159 -200
- package/dist/index.js.map +1 -1
- package/dist/reactive-args-BBucrU54.d.cts +32 -0
- package/dist/reactive-args-BBucrU54.d.ts +32 -0
- package/dist/testing/index.cjs +33 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +18 -0
- package/dist/testing/index.d.ts +18 -0
- package/dist/testing/index.js +33 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +42 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { Ref, JSX } from 'react';
|
|
3
|
-
import {
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React, { Ref, JSX } from 'react';
|
|
3
|
+
import { Reaction } from 'mobx';
|
|
4
|
+
import { M as MaybeGetter } from './reactive-args-BBucrU54.js';
|
|
5
|
+
export { t as toValue } from './reactive-args-BBucrU54.js';
|
|
6
|
+
|
|
7
|
+
declare const serviceType: unique symbol;
|
|
8
|
+
/** Class tokens and typed symbols are also valid tsyringe injection tokens. */
|
|
9
|
+
type ServiceToken<T extends object> = (new (...args: any[]) => T) | (symbol & {
|
|
10
|
+
readonly [serviceType]: T;
|
|
11
|
+
});
|
|
12
|
+
type ServiceResolver = <T extends object>(token: ServiceToken<T>) => T;
|
|
13
|
+
declare function createServiceToken<T extends object>(description: string): ServiceToken<T>;
|
|
14
|
+
declare function ServiceProvider({ resolve, children }: {
|
|
15
|
+
resolve: ServiceResolver;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}): react_jsx_runtime.JSX.Element;
|
|
18
|
+
/** Synchronous construction scope, also useful outside React. Does not own services. */
|
|
19
|
+
declare function withInjectionScope<T>(resolve: ServiceResolver | undefined, construct: () => T): T;
|
|
20
|
+
/** Resolve during synchronous construction/onCreate, or inside withInjectionScope(). */
|
|
21
|
+
declare function inject<T extends object>(token: ServiceToken<T>): T;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Holder linking a component instance to its render reaction, so PropsBox
|
|
25
|
+
* can recognize "my own render is reading me" and skip tracking (React
|
|
26
|
+
* already delivers prop changes through memo — tracking would only schedule
|
|
27
|
+
* a redundant second render). Stable per React component instance; survives
|
|
28
|
+
* HMR instance swaps.
|
|
29
|
+
*/
|
|
30
|
+
interface RenderReactionHolder {
|
|
31
|
+
current: Reaction | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Minimal observer() for plain function components — re-renders when any
|
|
35
|
+
* observable read during render changes. Useful together with useBehavior()
|
|
36
|
+
* in codebases that don't (or don't yet) use Mantle components.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* const Toolbar = observer((props: Props) => {
|
|
41
|
+
* const size = useBehavior(() => withWindowSize());
|
|
42
|
+
* return <div>{size.width}px</div>;
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function observer<P extends object>(fc: ((props: P) => React.ReactElement | null) & {
|
|
47
|
+
displayName?: string;
|
|
48
|
+
}): (props: P) => React.ReactElement | null;
|
|
4
49
|
|
|
5
50
|
/** Options for the watch method */
|
|
6
51
|
interface WatchOptions {
|
|
@@ -9,32 +54,74 @@ interface WatchOptions {
|
|
|
9
54
|
/** Run callback immediately with current value */
|
|
10
55
|
fireImmediately?: boolean;
|
|
11
56
|
}
|
|
57
|
+
/** Options for the effect method */
|
|
58
|
+
interface EffectOptions {
|
|
59
|
+
/** Debounce the effect by N milliseconds */
|
|
60
|
+
delay?: number;
|
|
61
|
+
}
|
|
12
62
|
/**
|
|
13
63
|
* Error context passed to the onError handler
|
|
14
64
|
*/
|
|
15
65
|
interface MantleErrorContext {
|
|
16
66
|
/** The lifecycle phase where the error occurred */
|
|
17
|
-
phase: 'onLayoutMount' | 'onMount' | 'onUpdate' | 'onUnmount' | 'watch';
|
|
18
|
-
/** The
|
|
67
|
+
phase: 'onLayoutMount' | 'onMount' | 'onUpdate' | 'onUnmount' | 'watch' | 'effect' | 'sync';
|
|
68
|
+
/** The Component or Behavior class name */
|
|
19
69
|
name: string;
|
|
20
|
-
/** Whether the error came from a Behavior (true) or a
|
|
70
|
+
/** Whether the error came from a Behavior (true) or a Component (false) */
|
|
21
71
|
isBehavior: boolean;
|
|
22
72
|
}
|
|
23
73
|
/**
|
|
24
74
|
* Global configuration options for mobx-mantle
|
|
25
75
|
*/
|
|
26
76
|
interface MantleConfig {
|
|
27
|
-
/**
|
|
77
|
+
/** Application service resolver, captured at construction. Explicit service scopes override it. */
|
|
78
|
+
resolveService?: ServiceResolver;
|
|
79
|
+
/** Whether to automatically make Component/Behavior instances observable (default: true) */
|
|
28
80
|
autoObservable?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Cache per-class prototype annotation data (getters, methods) so repeated
|
|
83
|
+
* instantiations of the same class skip the prototype walk (default: true).
|
|
84
|
+
* Turn off only if a class's prototype is mutated between instantiations.
|
|
85
|
+
*/
|
|
86
|
+
cacheAnnotations?: boolean;
|
|
29
87
|
/** Global error handler for lifecycle errors. Defaults to console.error. */
|
|
30
88
|
onError?: (error: unknown, context: MantleErrorContext) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Set true to opt into process-wide permissive MobX actions (default: false).
|
|
91
|
+
* By default Mantle preserves the host's MobX policy. Synchronous methods
|
|
92
|
+
* and lifecycle callbacks are actions; async continuations should use
|
|
93
|
+
* runInAction. Configure before the first component or behavior is created.
|
|
94
|
+
*/
|
|
95
|
+
manageMobxActions?: boolean;
|
|
31
96
|
}
|
|
32
97
|
/**
|
|
33
98
|
* Configure global defaults for mobx-mantle.
|
|
34
|
-
* Settings can still be overridden per-
|
|
99
|
+
* Settings can still be overridden per-component in createComponent options.
|
|
35
100
|
*/
|
|
36
101
|
declare function configure(config: MantleConfig): void;
|
|
37
102
|
|
|
103
|
+
/**
|
|
104
|
+
* A watch/effect registration. `create` builds the underlying MobX reaction
|
|
105
|
+
* and returns its disposer. Specs registered before mount are kept so the
|
|
106
|
+
* reaction can be re-created if the host unmounts and remounts with the same
|
|
107
|
+
* instance — React StrictMode does exactly this in development.
|
|
108
|
+
*/
|
|
109
|
+
interface ReactiveSpec {
|
|
110
|
+
create: () => () => void;
|
|
111
|
+
stopped: boolean;
|
|
112
|
+
dispose: (() => void) | null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Placeholder returned by sync() during construction. The wrapper constructor
|
|
117
|
+
* scans own fields right after onCreate, finds which key holds each marker,
|
|
118
|
+
* swaps in the initial value, and registers the hidden sync effect for that
|
|
119
|
+
* key. (Same post-onCreate scan window that behavior collection uses.)
|
|
120
|
+
*/
|
|
121
|
+
declare class SyncMarker {
|
|
122
|
+
readonly source: () => unknown;
|
|
123
|
+
constructor(source: () => unknown);
|
|
124
|
+
}
|
|
38
125
|
/**
|
|
39
126
|
* Base class for behaviors. Provides lifecycle method signatures for IDE autocomplete.
|
|
40
127
|
* Extend this class and wrap with createBehavior() to create a factory.
|
|
@@ -50,17 +137,50 @@ declare function configure(config: MantleConfig): void;
|
|
|
50
137
|
* ```
|
|
51
138
|
*/
|
|
52
139
|
declare class Behavior {
|
|
140
|
+
constructor();
|
|
141
|
+
inject<T extends object>(token: ServiceToken<T>): T;
|
|
53
142
|
/** @internal */
|
|
54
143
|
_watchDisposers: (() => void)[];
|
|
144
|
+
/** @internal — pre-mount watch/effect registrations, materialized at mount */
|
|
145
|
+
_reactiveSpecs: ReactiveSpec[];
|
|
146
|
+
/** @internal — child behaviors declared as fields, collected at construction */
|
|
147
|
+
_behaviors: BehaviorEntry[];
|
|
148
|
+
/** @internal — true after the parent Component first mounts */
|
|
149
|
+
_mounted: boolean;
|
|
150
|
+
/** @internal — set when effects clean up so StrictMode replay can resurrect pre-mount watchers */
|
|
151
|
+
_wasUnmounted: boolean;
|
|
152
|
+
/** @internal — sync() markers awaiting the post-onCreate field scan; null once construction completes */
|
|
153
|
+
_pendingSyncs: SyncMarker[] | null;
|
|
154
|
+
/** @internal — true while the hidden sync effect writes a mirrored field (dev write-guard) */
|
|
155
|
+
_syncWriting: boolean;
|
|
55
156
|
onCreate?(...args: any[]): void;
|
|
56
157
|
onLayoutMount?(): void | (() => void);
|
|
57
158
|
onMount?(): void | (() => void);
|
|
58
159
|
onUnmount?(): void;
|
|
160
|
+
/**
|
|
161
|
+
* Register a cleanup function to run automatically on unmount.
|
|
162
|
+
* Returns a function that can be called for early cleanup.
|
|
163
|
+
*
|
|
164
|
+
* Cleanups are one-shot: they are not re-created during React StrictMode's
|
|
165
|
+
* same-instance effect replay. Call this from onMount (which is replayed),
|
|
166
|
+
* or use effect() for a replay-safe setup/teardown pair.
|
|
167
|
+
*/
|
|
168
|
+
addCleanup(cleanup: () => void): () => void;
|
|
169
|
+
/** @internal — addCleanup without the pre-mount dev warning (used by watch/effect) */
|
|
170
|
+
_addCleanup(cleanup: () => void): () => void;
|
|
59
171
|
/**
|
|
60
172
|
* Watch a reactive expression and run a callback when it changes.
|
|
61
|
-
* Automatically disposed on unmount
|
|
173
|
+
* Automatically disposed on unmount and re-created during React StrictMode's
|
|
174
|
+
* same-instance effect replay.
|
|
62
175
|
*
|
|
63
|
-
*
|
|
176
|
+
* Safe to call from onCreate: registration is recorded and comes alive
|
|
177
|
+
* when the parent commits (just before first paint), so the watcher
|
|
178
|
+
* tracks observable fields correctly and renders that React discards
|
|
179
|
+
* never leak reactions.
|
|
180
|
+
*
|
|
181
|
+
* @param source - Reactive expression (getter) to watch, or a MaybeGetter
|
|
182
|
+
* argument passed through as-is. To watch a value that is itself a
|
|
183
|
+
* function, wrap it: `watch(() => this.callback, …)`
|
|
64
184
|
* @param callback - Called when the expression result changes
|
|
65
185
|
* @param options - Optional configuration (delay, fireImmediately)
|
|
66
186
|
* @returns Dispose function for early teardown
|
|
@@ -73,7 +193,52 @@ declare class Behavior {
|
|
|
73
193
|
* }
|
|
74
194
|
* ```
|
|
75
195
|
*/
|
|
76
|
-
watch<T>(
|
|
196
|
+
watch<T>(source: MaybeGetter<T>, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
197
|
+
/**
|
|
198
|
+
* Run a side effect that auto-tracks reactive dependencies.
|
|
199
|
+
* Re-runs whenever any accessed observable changes.
|
|
200
|
+
* Automatically disposed on unmount.
|
|
201
|
+
*
|
|
202
|
+
* Best for simple synchronization (DOM updates, logging). For complex
|
|
203
|
+
* side effects with explicit triggers, prefer `watch()`.
|
|
204
|
+
*
|
|
205
|
+
* @param fn - Effect function. May return a cleanup function.
|
|
206
|
+
* @param options - Optional configuration (delay)
|
|
207
|
+
* @returns Dispose function for early teardown
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```tsx
|
|
211
|
+
* onCreate() {
|
|
212
|
+
* this.effect(() => {
|
|
213
|
+
* console.log('Current value:', this.value);
|
|
214
|
+
* });
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
effect(fn: () => void | (() => void), options?: EffectOptions): () => void;
|
|
219
|
+
/**
|
|
220
|
+
* Normalize a MaybeGetter argument into an ordinary field that stays
|
|
221
|
+
* current. Call once in onCreate (or a field initializer) and assign the
|
|
222
|
+
* result to a field; everywhere else, read the field like normal state:
|
|
223
|
+
*
|
|
224
|
+
* ```tsx
|
|
225
|
+
* url!: string;
|
|
226
|
+
*
|
|
227
|
+
* onCreate(url: MaybeGetter<string>) {
|
|
228
|
+
* this.url = this.sync(url); // the one convention line
|
|
229
|
+
* this.watch(() => this.url, (u) => this.load(u));
|
|
230
|
+
* }
|
|
231
|
+
* refresh() { this.load(this.url); } // plain read, always current
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* - Plain value → the field just holds it (no effect registered).
|
|
235
|
+
* - Getter → a hidden effect keeps the field updated whenever the getter's
|
|
236
|
+
* observable sources change (alive from mount, like watch/effect).
|
|
237
|
+
*
|
|
238
|
+
* The sync is one-way (argument → field). Don't write to the field from
|
|
239
|
+
* outside: the next source change overwrites it (dev mode warns).
|
|
240
|
+
*/
|
|
241
|
+
sync<T>(source: MaybeGetter<T>): T;
|
|
77
242
|
/** @internal */
|
|
78
243
|
_disposeWatchers(): void;
|
|
79
244
|
}
|
|
@@ -122,19 +287,19 @@ type BehaviorArgs<T extends new (...args: any[]) => any> = ConstructorParams<T>
|
|
|
122
287
|
* export const withDrag = createBehavior(DragTrait);
|
|
123
288
|
* ```
|
|
124
289
|
*
|
|
125
|
-
* @example Using in a
|
|
290
|
+
* @example Using in a Component
|
|
126
291
|
* ```tsx
|
|
127
|
-
* class Editor extends
|
|
292
|
+
* class Editor extends Component<Props> {
|
|
128
293
|
* canvas = this.ref<HTMLCanvasElement>();
|
|
129
294
|
*
|
|
130
295
|
* // No `new` keyword — factory function
|
|
131
296
|
* drag = withDrag(this.canvas);
|
|
132
297
|
* autosave = withAutosave('/api/save', 5000);
|
|
133
298
|
* }
|
|
134
|
-
* export default
|
|
299
|
+
* export default createComponent(Editor);
|
|
135
300
|
* ```
|
|
136
301
|
*
|
|
137
|
-
* The `with` prefix convention signals that the
|
|
302
|
+
* The `with` prefix convention signals that the component manages this behavior's lifecycle.
|
|
138
303
|
*/
|
|
139
304
|
/**
|
|
140
305
|
* Type that supports both `new` and direct call syntax
|
|
@@ -147,78 +312,77 @@ declare function createBehavior<T extends new (...args: any[]) => any>(Def: T, o
|
|
|
147
312
|
autoObservable?: boolean;
|
|
148
313
|
}): BehaviorFactory<BehaviorArgs<T>, InstanceType<T>>;
|
|
149
314
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*/
|
|
153
|
-
interface DecoratorContext {
|
|
154
|
-
kind: 'field' | 'method' | 'getter' | 'setter' | 'accessor' | 'class';
|
|
315
|
+
type Context = {
|
|
316
|
+
kind: string;
|
|
155
317
|
name: string | symbol;
|
|
156
|
-
metadata
|
|
157
|
-
|
|
318
|
+
metadata?: Record<symbol, unknown>;
|
|
319
|
+
static?: boolean;
|
|
320
|
+
private?: boolean;
|
|
321
|
+
};
|
|
322
|
+
/** Plain fields in either TypeScript decorator mode; no accessor keyword needed. */
|
|
323
|
+
declare const observable: ((_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void) & {
|
|
324
|
+
ref: (_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
325
|
+
shallow: (_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
326
|
+
deep: (_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
327
|
+
struct: (_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
328
|
+
};
|
|
329
|
+
/** Bound prototype method, or an arrow-function field (already bound); synchronous writes are batched. */
|
|
330
|
+
declare const action: (target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
331
|
+
declare const computed: (_target: any, key: string | symbol | Context, descriptor?: PropertyDescriptor) => void;
|
|
332
|
+
|
|
158
333
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* }
|
|
166
|
-
* export default createView(Counter);
|
|
167
|
-
* ```
|
|
334
|
+
* Props holder built on MobX's public atom API. Reads are tracked like any
|
|
335
|
+
* observable. Writes come in two flavors:
|
|
336
|
+
* - setSilently: update the value without notifying observers — safe during
|
|
337
|
+
* React's render phase (see Component._syncProps)
|
|
338
|
+
* - set: update and notify observers — called from useLayoutEffect after
|
|
339
|
+
* React finishes the render pass
|
|
168
340
|
*/
|
|
169
|
-
declare
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
341
|
+
declare class PropsBox<P> {
|
|
342
|
+
private _atom;
|
|
343
|
+
private _value;
|
|
344
|
+
/**
|
|
345
|
+
* @internal The owning component's render reaction. Reads coming from it
|
|
346
|
+
* are not tracked: React already re-renders the component on prop change
|
|
347
|
+
* (via memo), so letting the render reaction observe the props atom would
|
|
348
|
+
* only schedule a redundant second render after every prop change.
|
|
349
|
+
* Computeds, watchers, and other components track normally.
|
|
350
|
+
*/
|
|
351
|
+
_renderReaction: RenderReactionHolder | null;
|
|
352
|
+
constructor(value: P, name: string);
|
|
353
|
+
get(): P;
|
|
354
|
+
setSilently(value: P): void;
|
|
355
|
+
set(value: P): void;
|
|
175
356
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* ```tsx
|
|
181
|
-
* class Counter extends View {
|
|
182
|
-
* @observable count = 0;
|
|
183
|
-
*
|
|
184
|
-
* @action increment() {
|
|
185
|
-
* this.count++;
|
|
186
|
-
* }
|
|
187
|
-
* }
|
|
188
|
-
* export default createView(Counter);
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
declare function action(_value: Function, context: DecoratorContext): void;
|
|
192
|
-
/**
|
|
193
|
-
* Marks a getter as computed.
|
|
194
|
-
* Note: Getters are automatically computed in autoObservable mode,
|
|
195
|
-
* but this decorator is useful for explicit annotation.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```tsx
|
|
199
|
-
* class Counter extends View {
|
|
200
|
-
* @observable count = 0;
|
|
201
|
-
*
|
|
202
|
-
* @computed get doubled() {
|
|
203
|
-
* return this.count * 2;
|
|
204
|
-
* }
|
|
205
|
-
* }
|
|
206
|
-
* export default createView(Counter);
|
|
207
|
-
* ```
|
|
208
|
-
*/
|
|
209
|
-
declare function computed(_value: Function, context: DecoratorContext): void;
|
|
210
|
-
|
|
211
|
-
declare class View<P = {}> {
|
|
357
|
+
type ComponentConstructor<C extends Component<any> = Component<any>> = abstract new (...args: any[]) => C;
|
|
358
|
+
declare class Component<P = {}> {
|
|
212
359
|
/** @internal */
|
|
213
|
-
_propsBox:
|
|
360
|
+
_propsBox: PropsBox<P>;
|
|
361
|
+
constructor(props?: P);
|
|
214
362
|
get props(): P;
|
|
215
|
-
/**
|
|
363
|
+
/** Resolve through the scope captured during construction; preserve service identity. */
|
|
364
|
+
inject<T extends object>(token: ServiceToken<T>): T;
|
|
365
|
+
/** Return the immediate ancestor in the live Mantle view tree. */
|
|
366
|
+
getParent(): Component<any> | undefined;
|
|
367
|
+
/** Find the nearest parent with the supplied logical model identity. */
|
|
368
|
+
findParent<C extends Component<any>>(type: ComponentConstructor<C>): C | undefined;
|
|
369
|
+
/** Return all Mantle parents, ordered from the immediate parent to the root. */
|
|
370
|
+
getParents(): readonly Component<any>[];
|
|
371
|
+
/** Return the highest Mantle ancestor, or this instance when already root. */
|
|
372
|
+
getRoot(): Component<any>;
|
|
373
|
+
/** @internal — called by createComponent to silently update props during render */
|
|
216
374
|
_syncProps(value: P): void;
|
|
217
375
|
forwardRef?: Ref<any>;
|
|
218
376
|
/** @internal */
|
|
219
377
|
_behaviors: BehaviorEntry[];
|
|
220
378
|
/** @internal */
|
|
221
379
|
_watchDisposers: (() => void)[];
|
|
380
|
+
/** @internal — pre-mount watch/effect registrations, materialized at mount */
|
|
381
|
+
_reactiveSpecs: ReactiveSpec[];
|
|
382
|
+
/** @internal — true after the first (layout) mount */
|
|
383
|
+
_mounted: boolean;
|
|
384
|
+
/** @internal — set when effects clean up so StrictMode replay can resurrect watchers */
|
|
385
|
+
_wasUnmounted: boolean;
|
|
222
386
|
onCreate?(props: P): void;
|
|
223
387
|
onLayoutMount?(): void | (() => void);
|
|
224
388
|
onMount?(): void | (() => void);
|
|
@@ -227,18 +391,33 @@ declare class View<P = {}> {
|
|
|
227
391
|
ref<T extends HTMLElement = HTMLElement>(): {
|
|
228
392
|
current: T | null;
|
|
229
393
|
};
|
|
394
|
+
/**
|
|
395
|
+
* Register a cleanup function to run automatically on unmount.
|
|
396
|
+
* Returns a function that can be called for early cleanup.
|
|
397
|
+
*
|
|
398
|
+
* Cleanups are one-shot: they are not re-created during React StrictMode's
|
|
399
|
+
* same-instance effect replay. Call this from onMount (which is replayed),
|
|
400
|
+
* or use effect() for a replay-safe setup/teardown pair.
|
|
401
|
+
*/
|
|
402
|
+
addCleanup(cleanup: () => void): () => void;
|
|
403
|
+
/** @internal — addCleanup without the pre-mount dev warning (used by watch/effect) */
|
|
404
|
+
_addCleanup(cleanup: () => void): () => void;
|
|
230
405
|
/**
|
|
231
406
|
* Watch a reactive expression and run a callback when it changes.
|
|
232
|
-
* Automatically disposed on unmount.
|
|
407
|
+
* Automatically disposed on unmount. Watchers declared before mount
|
|
408
|
+
* (field initializers, onCreate) are re-created during React StrictMode's
|
|
409
|
+
* same-instance effect replay.
|
|
233
410
|
*
|
|
234
|
-
* @param
|
|
411
|
+
* @param source - Reactive expression (getter) to watch, or a MaybeGetter
|
|
412
|
+
* argument passed through as-is. To watch a value that is itself a
|
|
413
|
+
* function, wrap it: `watch(() => this.callback, …)`
|
|
235
414
|
* @param callback - Called when the expression result changes
|
|
236
415
|
* @param options - Optional configuration (delay, fireImmediately)
|
|
237
416
|
* @returns Dispose function for early teardown
|
|
238
417
|
*
|
|
239
418
|
* @example
|
|
240
419
|
* ```tsx
|
|
241
|
-
*
|
|
420
|
+
* onMount() {
|
|
242
421
|
* this.watch(
|
|
243
422
|
* () => this.query,
|
|
244
423
|
* async (query) => {
|
|
@@ -251,7 +430,42 @@ declare class View<P = {}> {
|
|
|
251
430
|
* }
|
|
252
431
|
* ```
|
|
253
432
|
*/
|
|
254
|
-
watch<T>(
|
|
433
|
+
watch<T>(source: MaybeGetter<T>, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
434
|
+
/**
|
|
435
|
+
* Run a side effect that auto-tracks reactive dependencies.
|
|
436
|
+
* Re-runs whenever any accessed observable changes.
|
|
437
|
+
* Automatically disposed on unmount. Effects declared before mount
|
|
438
|
+
* (field initializers, onCreate) are re-created during React StrictMode's
|
|
439
|
+
* same-instance effect replay.
|
|
440
|
+
*
|
|
441
|
+
* Best for simple synchronization (DOM updates, logging). For complex
|
|
442
|
+
* side effects with explicit triggers, prefer `watch()`.
|
|
443
|
+
*
|
|
444
|
+
* @param fn - Effect function. May return a cleanup function.
|
|
445
|
+
* @param options - Optional configuration (delay)
|
|
446
|
+
* @returns Dispose function for early teardown
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```tsx
|
|
450
|
+
* onMount() {
|
|
451
|
+
* this.effect(() => {
|
|
452
|
+
* document.title = `${this.items.length} items`;
|
|
453
|
+
* });
|
|
454
|
+
* }
|
|
455
|
+
* ```
|
|
456
|
+
*
|
|
457
|
+
* @example With cleanup
|
|
458
|
+
* ```tsx
|
|
459
|
+
* onMount() {
|
|
460
|
+
* this.effect(() => {
|
|
461
|
+
* const handler = () => console.log(this.count);
|
|
462
|
+
* window.addEventListener('click', handler);
|
|
463
|
+
* return () => window.removeEventListener('click', handler);
|
|
464
|
+
* });
|
|
465
|
+
* }
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
effect(fn: () => void | (() => void), options?: EffectOptions): () => void;
|
|
255
469
|
/** @internal */
|
|
256
470
|
_disposeWatchers(): void;
|
|
257
471
|
/** @internal - Scan own properties for behavior instances and register them */
|
|
@@ -265,9 +479,143 @@ declare class View<P = {}> {
|
|
|
265
479
|
render?(): JSX.Element | null;
|
|
266
480
|
}
|
|
267
481
|
|
|
268
|
-
type PropsOf<
|
|
269
|
-
|
|
482
|
+
type PropsOf<C> = C extends Component<infer P> ? P : object;
|
|
483
|
+
/**
|
|
484
|
+
* Return type for createComponent.
|
|
485
|
+
*
|
|
486
|
+
* Simple callable signature that works with libraries expecting ComponentType<P>
|
|
487
|
+
* or strict function components (react-window, react-virtualized, etc.).
|
|
488
|
+
*
|
|
489
|
+
* Uses ReactElement | null rather than React.FC's looser ReactNode return type.
|
|
490
|
+
*/
|
|
491
|
+
type MantleComponent<P> = (props: P) => React.ReactElement | null;
|
|
492
|
+
/**
|
|
493
|
+
* Return type for createForwardRef when you need typed ref forwarding.
|
|
494
|
+
*
|
|
495
|
+
* Use this when you need to forward refs to DOM elements or child components
|
|
496
|
+
* and want TypeScript to know the ref type.
|
|
497
|
+
*/
|
|
498
|
+
type ForwardRefMantleComponent<P, RefType> = ((props: P) => React.ReactElement | null) & React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<RefType>>;
|
|
499
|
+
declare function createComponent<C extends Component<any>>(ComponentClass: new (...args: any[]) => C, templateOrOptions?: ((vm: C) => JSX.Element) | {
|
|
500
|
+
autoObservable?: boolean;
|
|
501
|
+
}): MantleComponent<PropsOf<C>>;
|
|
502
|
+
/**
|
|
503
|
+
* Creates a React component with typed ref forwarding.
|
|
504
|
+
*
|
|
505
|
+
* Use this instead of createComponent when you need to forward refs to DOM elements
|
|
506
|
+
* or child components and want proper TypeScript support for the ref type.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```tsx
|
|
510
|
+
* class FancyInput extends Component<Props> {
|
|
511
|
+
* render() {
|
|
512
|
+
* return <input ref={this.forwardRef} className="fancy" />;
|
|
513
|
+
* }
|
|
514
|
+
* }
|
|
515
|
+
*
|
|
516
|
+
* const FancyInputComponent = createForwardRef<HTMLInputElement>(FancyInput);
|
|
517
|
+
*
|
|
518
|
+
* // Parent gets typed ref:
|
|
519
|
+
* const inputRef = useRef<HTMLInputElement>(null);
|
|
520
|
+
* <FancyInputComponent ref={inputRef} />
|
|
521
|
+
* ```
|
|
522
|
+
*/
|
|
523
|
+
declare function createForwardRef<RefType, C extends Component<any> = Component<any>>(ComponentClass: new (...args: any[]) => C, templateOrOptions?: ((vm: C) => JSX.Element) | {
|
|
270
524
|
autoObservable?: boolean;
|
|
271
|
-
}):
|
|
525
|
+
}): ForwardRefMantleComponent<PropsOf<C>, RefType>;
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Host a behavior inside a plain React function component. The behavior gets
|
|
529
|
+
* the same lifecycle relay a Mantle Component would give it: onLayoutMount in
|
|
530
|
+
* the layout phase, onMount after paint, watchers alive from commit, full
|
|
531
|
+
* teardown at unmount, and StrictMode remount resurrection.
|
|
532
|
+
*
|
|
533
|
+
* The instance is created once per mount lifetime, from a factory so nothing
|
|
534
|
+
* is constructed on re-renders. It is returned as-is — wrap the component in
|
|
535
|
+
* observer() (from mobx-mantle) so renders track the behavior's observables:
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* ```tsx
|
|
539
|
+
* const Toolbar = observer(() => {
|
|
540
|
+
* const size = useBehavior(() => withWindowSize());
|
|
541
|
+
* return <div>{size.width} × {size.height}</div>;
|
|
542
|
+
* });
|
|
543
|
+
* ```
|
|
544
|
+
*
|
|
545
|
+
* Note: the factory runs once, so getter arguments close over the first
|
|
546
|
+
* render's scope. Getters reading observables (a store, another behavior)
|
|
547
|
+
* stay live; getters reading a function component's props capture the first
|
|
548
|
+
* render's props object and go stale — pass observable sources instead.
|
|
549
|
+
*/
|
|
550
|
+
declare function useBehavior<T extends object>(create: () => T): T;
|
|
551
|
+
|
|
552
|
+
interface SharedOptions {
|
|
553
|
+
/**
|
|
554
|
+
* Persist the shared fields to localStorage under the key and restore
|
|
555
|
+
* them at startup, so a fresh window starts where the last one left off.
|
|
556
|
+
* Default true.
|
|
557
|
+
*/
|
|
558
|
+
persist?: boolean;
|
|
559
|
+
/**
|
|
560
|
+
* The fields to share. Defaults to the store's own observable data
|
|
561
|
+
* fields: not getters, not methods, not names starting with `_`.
|
|
562
|
+
*/
|
|
563
|
+
fields?: readonly string[];
|
|
564
|
+
}
|
|
565
|
+
interface ShareStoresOptions extends SharedOptions {
|
|
566
|
+
/** Key prefix for each store; the key is `${prefix}:${name}`. Default `shared`. */
|
|
567
|
+
prefix?: string;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Share a MobX store's state across every window of one application:
|
|
571
|
+
* other tabs, the frames a design tool hosts, anything on the same origin
|
|
572
|
+
* that imports the same module. Each window keeps its own store instance;
|
|
573
|
+
* values are mirrored, identity is not shared, and nothing goes through a
|
|
574
|
+
* server or a parent document.
|
|
575
|
+
*
|
|
576
|
+
* Mechanics, the web's own answer for two windows, packaged so it is never
|
|
577
|
+
* written by hand:
|
|
578
|
+
* - restore the store's fields from localStorage at startup (`persist`);
|
|
579
|
+
* - publish changes through a reaction to localStorage and a
|
|
580
|
+
* BroadcastChannel;
|
|
581
|
+
* - apply incoming changes from the channel or the `storage` event inside
|
|
582
|
+
* an action.
|
|
583
|
+
* Echo loops are bounded because a window only publishes when its
|
|
584
|
+
* serialized state changed, and only applies what differs from it.
|
|
585
|
+
*
|
|
586
|
+
* The one authoring rule: effects must derive from state — a `reaction`,
|
|
587
|
+
* `autorun`, or a component's `watch`/`effect` — never run inside setters,
|
|
588
|
+
* because a change that arrives from another window sets fields directly.
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* export const themeStore = shared(new ThemeStore(), 'theme');
|
|
592
|
+
*/
|
|
593
|
+
declare function shared<T extends object>(store: T, key: string, options?: SharedOptions): T;
|
|
594
|
+
/** Stop sharing a store (tests, teardown). The store keeps its current state. */
|
|
595
|
+
declare function unshare(store: object): void;
|
|
596
|
+
/**
|
|
597
|
+
* Share several stores at once, keyed by name: the one line an application
|
|
598
|
+
* writes at its entry point (a design tool's manifest, an app's main
|
|
599
|
+
* module) so every window that imports it wires the same stores.
|
|
600
|
+
*
|
|
601
|
+
* @example
|
|
602
|
+
* shareStores({ themeStore, navPreferences });
|
|
603
|
+
*/
|
|
604
|
+
declare function shareStores<T extends Record<string, object>>(stores: T, options?: ShareStoresOptions): T;
|
|
605
|
+
|
|
606
|
+
type ModelClass<C extends Component<any> = Component<any>> = new (...args: any[]) => C;
|
|
607
|
+
interface ModelSubstitution<C extends Component<any> = Component<any>> {
|
|
608
|
+
/** Runs for each instance instead of its original constructor. Supply data/callbacks only. */
|
|
609
|
+
state: () => object;
|
|
610
|
+
/** Required for integrated render() classes; optional for separate templates. */
|
|
611
|
+
template?: (model: C) => React.JSX.Element;
|
|
612
|
+
}
|
|
613
|
+
/** Construction policy. The mounted tree takes a snapshot; remount to change it. */
|
|
614
|
+
declare function ModelProvider({ models, children }: {
|
|
615
|
+
models: ReadonlyMap<ModelClass, ModelSubstitution>;
|
|
616
|
+
children?: React.ReactNode;
|
|
617
|
+
}): react_jsx_runtime.JSX.Element;
|
|
618
|
+
/** Logical identity works for real and substituted models. It does not fake instanceof. */
|
|
619
|
+
declare function isModel<C extends Component<any>>(model: object, type: abstract new (...args: any[]) => C): model is C;
|
|
272
620
|
|
|
273
|
-
export { Behavior, type MantleConfig, type MantleErrorContext,
|
|
621
|
+
export { Behavior, Component, type ComponentConstructor, type ForwardRefMantleComponent, type MantleComponent, type MantleConfig, type MantleErrorContext, MaybeGetter, type ModelClass, ModelProvider, type ModelSubstitution, ServiceProvider, type ServiceResolver, type ServiceToken, type ShareStoresOptions, type SharedOptions, Component as ViewModel, type WatchOptions, action, computed, configure, createBehavior, createComponent, createForwardRef, createServiceToken, inject, isModel, observable, observer, shareStores, shared, unshare, useBehavior, withInjectionScope };
|