mobx-mantle 0.3.7 → 0.7.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/README.md +1558 -722
- 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 +1237 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +468 -83
- package/dist/index.d.ts +468 -83
- package/dist/index.js +1223 -197
- 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.cjs
CHANGED
|
@@ -1,65 +1,31 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
Behavior: () => Behavior,
|
|
34
|
-
View: () => View,
|
|
35
|
-
ViewModel: () => View,
|
|
36
|
-
action: () => action3,
|
|
37
|
-
computed: () => computed3,
|
|
38
|
-
configure: () => configure,
|
|
39
|
-
createBehavior: () => createBehavior,
|
|
40
|
-
createView: () => createView,
|
|
41
|
-
observable: () => observable3
|
|
42
|
-
});
|
|
43
|
-
module.exports = __toCommonJS(index_exports);
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
44
2
|
|
|
45
|
-
|
|
46
|
-
var import_react = require("react");
|
|
47
|
-
var import_mobx2 = require("mobx");
|
|
48
|
-
var import_mobx_react_lite = require("mobx-react-lite");
|
|
3
|
+
var _chunkWNF647U6cjs = require('./chunk-WNF647U6.cjs');
|
|
49
4
|
|
|
50
|
-
// src/
|
|
51
|
-
var
|
|
5
|
+
// src/services.tsx
|
|
6
|
+
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
52
7
|
|
|
53
8
|
// src/config.ts
|
|
9
|
+
var _mobx = require('mobx'); var mobx = _interopRequireWildcard(_mobx);
|
|
54
10
|
var globalConfig = {
|
|
55
|
-
autoObservable: true
|
|
11
|
+
autoObservable: true,
|
|
12
|
+
cacheAnnotations: true,
|
|
13
|
+
manageMobxActions: false
|
|
56
14
|
};
|
|
15
|
+
var actionPolicyApplied = false;
|
|
16
|
+
function applyMobxActionPolicy() {
|
|
17
|
+
if (actionPolicyApplied) return;
|
|
18
|
+
actionPolicyApplied = true;
|
|
19
|
+
if (globalConfig.manageMobxActions === true) {
|
|
20
|
+
_mobx.configure.call(void 0, { enforceActions: "never" });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
57
23
|
function reportError(error, context) {
|
|
58
24
|
if (globalConfig.onError) {
|
|
59
25
|
globalConfig.onError(error, context);
|
|
60
26
|
} else {
|
|
61
27
|
console.error(
|
|
62
|
-
`[mobx-mantle] Error in ${context.isBehavior ? "behavior" : "
|
|
28
|
+
`[mobx-mantle] Error in ${context.isBehavior ? "behavior" : "component"} ${context.name}.${context.phase}():`,
|
|
63
29
|
error
|
|
64
30
|
);
|
|
65
31
|
}
|
|
@@ -68,18 +34,355 @@ function configure(config) {
|
|
|
68
34
|
Object.assign(globalConfig, config);
|
|
69
35
|
}
|
|
70
36
|
|
|
37
|
+
// src/services.tsx
|
|
38
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
39
|
+
function createServiceToken(description) {
|
|
40
|
+
return Symbol(description);
|
|
41
|
+
}
|
|
42
|
+
var ServiceContext = _react2.default.createContext(void 0);
|
|
43
|
+
function ServiceProvider({ resolve, children }) {
|
|
44
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ServiceContext.Provider, { value: resolve, children });
|
|
45
|
+
}
|
|
46
|
+
var constructingScope;
|
|
47
|
+
var scopes = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
function runWithScope(scope, construct) {
|
|
49
|
+
const previous = constructingScope;
|
|
50
|
+
constructingScope = scope;
|
|
51
|
+
try {
|
|
52
|
+
return construct();
|
|
53
|
+
} finally {
|
|
54
|
+
constructingScope = previous;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function withInjectionScope(resolve, construct) {
|
|
58
|
+
return runWithScope({ resolve: _nullishCoalesce(resolve, () => ( globalConfig.resolveService)), values: /* @__PURE__ */ new WeakSet() }, construct);
|
|
59
|
+
}
|
|
60
|
+
function captureServiceScope(owner) {
|
|
61
|
+
scopes.set(owner, _nullishCoalesce(constructingScope, () => ( { resolve: globalConfig.resolveService, values: /* @__PURE__ */ new WeakSet() })));
|
|
62
|
+
}
|
|
63
|
+
function getServiceResolver(owner) {
|
|
64
|
+
return _optionalChain([scopes, 'access', _2 => _2.get, 'call', _3 => _3(owner), 'optionalAccess', _4 => _4.resolve]);
|
|
65
|
+
}
|
|
66
|
+
function resolveService(owner, token) {
|
|
67
|
+
return resolveInScope(scopes.get(owner), token);
|
|
68
|
+
}
|
|
69
|
+
function inject(token) {
|
|
70
|
+
if (!constructingScope) {
|
|
71
|
+
throw new Error("[mobx-mantle] inject() requires an active construction scope. Use this.inject() in later methods, or withInjectionScope() outside React.");
|
|
72
|
+
}
|
|
73
|
+
return resolveInScope(constructingScope, token);
|
|
74
|
+
}
|
|
75
|
+
function resolveInScope(scope, token) {
|
|
76
|
+
if (!_optionalChain([scope, 'optionalAccess', _5 => _5.resolve])) throw new Error("[mobx-mantle] Service injection requires configure({ resolveService }), a ServiceProvider, or withInjectionScope() during construction.");
|
|
77
|
+
const value = scope.resolve(token);
|
|
78
|
+
if ((typeof value !== "object" || value === null) && typeof value !== "function") {
|
|
79
|
+
throw new Error("[mobx-mantle] Services must be objects or functions; wrap primitive configuration in an object.");
|
|
80
|
+
}
|
|
81
|
+
scope.values.add(value);
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function isServiceValue(owner, value) {
|
|
85
|
+
return _nullishCoalesce(_optionalChain([scopes, 'access', _6 => _6.get, 'call', _7 => _7(owner), 'optionalAccess', _8 => _8.values, 'access', _9 => _9.has, 'call', _10 => _10(value)]), () => ( false));
|
|
86
|
+
}
|
|
87
|
+
function withOwnerServiceScope(owner, construct) {
|
|
88
|
+
const scope = scopes.get(owner);
|
|
89
|
+
if (!scope) throw new Error("[mobx-mantle] Missing owner service scope.");
|
|
90
|
+
return runWithScope(scope, construct);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/model-scope.tsx
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
var ModelContext = _react2.default.createContext(void 0);
|
|
97
|
+
function ModelProvider({ models, children }) {
|
|
98
|
+
const [snapshot] = _react2.default.useState(() => new Map(Array.from(models, ([type, replacement]) => [type, { ...replacement }])));
|
|
99
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModelContext.Provider, { value: snapshot, children });
|
|
100
|
+
}
|
|
101
|
+
var identities = /* @__PURE__ */ new WeakMap();
|
|
102
|
+
function setModelIdentity(model, type) {
|
|
103
|
+
identities.set(model, type);
|
|
104
|
+
}
|
|
105
|
+
function isModel(model, type) {
|
|
106
|
+
const logical = identities.get(model);
|
|
107
|
+
return model instanceof type || logical === type || !!logical && logical.prototype instanceof type;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/mantle.tsx
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
// src/observer.ts
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? _react.useLayoutEffect : _react.useEffect;
|
|
118
|
+
var uncommittedReactionRegistry = typeof FinalizationRegistry !== "undefined" ? new FinalizationRegistry((adm) => {
|
|
119
|
+
_optionalChain([adm, 'access', _11 => _11.reaction, 'optionalAccess', _12 => _12.dispose, 'call', _13 => _13()]);
|
|
120
|
+
adm.reaction = null;
|
|
121
|
+
}) : void 0;
|
|
122
|
+
if (process.env.NODE_ENV !== "production" && !uncommittedReactionRegistry) {
|
|
123
|
+
console.warn(
|
|
124
|
+
"[mobx-mantle] FinalizationRegistry is not available in this environment. Reactions created for renders that React discards cannot be cleaned up, which can leak under Suspense and concurrent rendering."
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
var isServer = typeof window === "undefined";
|
|
128
|
+
var trackedComponents = /* @__PURE__ */ new WeakSet();
|
|
129
|
+
function createReaction(adm) {
|
|
130
|
+
adm.reaction = new (0, _mobx.Reaction)(`mantle-observer(${adm.name})`, () => {
|
|
131
|
+
adm.stateVersion = /* @__PURE__ */ Symbol();
|
|
132
|
+
_optionalChain([adm, 'access', _14 => _14.onStoreChange, 'optionalCall', _15 => _15()]);
|
|
133
|
+
});
|
|
134
|
+
if (adm.holder) {
|
|
135
|
+
adm.holder.current = adm.reaction;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function useMantleObserver(render, name, holder) {
|
|
139
|
+
if (isServer) {
|
|
140
|
+
return render();
|
|
141
|
+
}
|
|
142
|
+
const admRef = _react.useRef.call(void 0, null);
|
|
143
|
+
if (!admRef.current) {
|
|
144
|
+
const adm2 = {
|
|
145
|
+
reaction: null,
|
|
146
|
+
onStoreChange: null,
|
|
147
|
+
stateVersion: /* @__PURE__ */ Symbol(),
|
|
148
|
+
name,
|
|
149
|
+
holder,
|
|
150
|
+
subscribe(onStoreChange) {
|
|
151
|
+
_optionalChain([uncommittedReactionRegistry, 'optionalAccess', _16 => _16.unregister, 'call', _17 => _17(adm2)]);
|
|
152
|
+
adm2.onStoreChange = onStoreChange;
|
|
153
|
+
if (!adm2.reaction) {
|
|
154
|
+
createReaction(adm2);
|
|
155
|
+
adm2.stateVersion = /* @__PURE__ */ Symbol();
|
|
156
|
+
onStoreChange();
|
|
157
|
+
}
|
|
158
|
+
return () => {
|
|
159
|
+
adm2.onStoreChange = null;
|
|
160
|
+
_optionalChain([adm2, 'access', _18 => _18.reaction, 'optionalAccess', _19 => _19.dispose, 'call', _20 => _20()]);
|
|
161
|
+
adm2.reaction = null;
|
|
162
|
+
if (adm2.holder) {
|
|
163
|
+
adm2.holder.current = null;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
getSnapshot() {
|
|
168
|
+
return adm2.stateVersion;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
admRef.current = adm2;
|
|
172
|
+
}
|
|
173
|
+
const adm = admRef.current;
|
|
174
|
+
adm.holder = holder;
|
|
175
|
+
if (!adm.reaction) {
|
|
176
|
+
createReaction(adm);
|
|
177
|
+
_optionalChain([uncommittedReactionRegistry, 'optionalAccess', _21 => _21.register, 'call', _22 => _22(admRef, adm, adm)]);
|
|
178
|
+
}
|
|
179
|
+
_react.useSyncExternalStore.call(void 0, adm.subscribe, adm.getSnapshot, adm.getSnapshot);
|
|
180
|
+
let result;
|
|
181
|
+
let didThrow = false;
|
|
182
|
+
let thrown;
|
|
183
|
+
adm.reaction.track(() => {
|
|
184
|
+
try {
|
|
185
|
+
result = render();
|
|
186
|
+
} catch (e) {
|
|
187
|
+
didThrow = true;
|
|
188
|
+
thrown = e;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
if (didThrow) {
|
|
192
|
+
throw thrown;
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
function observer(fc) {
|
|
197
|
+
const name = fc.displayName || fc.name || "observed";
|
|
198
|
+
const Observed = (props) => useMantleObserver(() => fc(props), name);
|
|
199
|
+
Observed.displayName = `observer(${name})`;
|
|
200
|
+
const Memoized = _react.memo.call(void 0, Observed);
|
|
201
|
+
trackedComponents.add(Memoized);
|
|
202
|
+
return Memoized;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/decorators.ts
|
|
206
|
+
|
|
207
|
+
var ANNOTATIONS = /* @__PURE__ */ Symbol("mantle:annotations");
|
|
208
|
+
var legacy = /* @__PURE__ */ new WeakMap();
|
|
209
|
+
function annotation(value, kind) {
|
|
210
|
+
return function(_target, key, descriptor) {
|
|
211
|
+
let map;
|
|
212
|
+
let name;
|
|
213
|
+
if (typeof key === "object") {
|
|
214
|
+
if (key.static || key.private || key.kind !== kind) {
|
|
215
|
+
throw new Error(`[mobx-mantle] This decorator requires a public instance ${kind}. Use an ordinary field, not an auto-accessor, for @observable.`);
|
|
216
|
+
}
|
|
217
|
+
if (!key.metadata) throw new Error("[mobx-mantle] TC39 decorators require Symbol.metadata. Load its polyfill before decorated classes.");
|
|
218
|
+
if (!Object.prototype.hasOwnProperty.call(key.metadata, ANNOTATIONS)) key.metadata[ANNOTATIONS] = /* @__PURE__ */ Object.create(null);
|
|
219
|
+
map = key.metadata[ANNOTATIONS];
|
|
220
|
+
name = key.name;
|
|
221
|
+
} else {
|
|
222
|
+
if (typeof _target === "function" || kind === "method" && typeof _optionalChain([descriptor, 'optionalAccess', _23 => _23.value]) !== "function" || kind === "getter" && !_optionalChain([descriptor, 'optionalAccess', _24 => _24.get]) || kind === "field" && descriptor) {
|
|
223
|
+
throw new Error(`[mobx-mantle] This decorator requires a public instance ${kind}.`);
|
|
224
|
+
}
|
|
225
|
+
map = _nullishCoalesce(legacy.get(_target), () => ( /* @__PURE__ */ Object.create(null)));
|
|
226
|
+
legacy.set(_target, map);
|
|
227
|
+
name = key;
|
|
228
|
+
}
|
|
229
|
+
map[name] = value;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
var observable2 = Object.assign(annotation(mobx.observable, "field"), {
|
|
233
|
+
ref: annotation(mobx.observable.ref, "field"),
|
|
234
|
+
shallow: annotation(mobx.observable.shallow, "field"),
|
|
235
|
+
deep: annotation(mobx.observable.deep, "field"),
|
|
236
|
+
struct: annotation(mobx.observable.struct, "field")
|
|
237
|
+
});
|
|
238
|
+
var actionMethod = annotation(mobx.action.bound, "method");
|
|
239
|
+
var actionField = annotation(mobx.action, "field");
|
|
240
|
+
var action2 = function(target, key, descriptor) {
|
|
241
|
+
const isField = typeof key === "object" ? key.kind === "field" : !descriptor;
|
|
242
|
+
return (isField ? actionField : actionMethod)(target, key, descriptor);
|
|
243
|
+
};
|
|
244
|
+
var computed2 = annotation(mobx.computed, "getter");
|
|
245
|
+
function getAnnotations(instance) {
|
|
246
|
+
const chain = [];
|
|
247
|
+
for (let proto = Object.getPrototypeOf(instance); proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) chain.unshift(proto);
|
|
248
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
249
|
+
for (const proto of chain) {
|
|
250
|
+
const constructor = proto.constructor;
|
|
251
|
+
const symbol = Symbol.metadata;
|
|
252
|
+
const metadata = symbol && Object.prototype.hasOwnProperty.call(constructor, symbol) ? constructor[symbol] : void 0;
|
|
253
|
+
const modern = metadata && Object.prototype.hasOwnProperty.call(metadata, ANNOTATIONS) ? metadata[ANNOTATIONS] : void 0;
|
|
254
|
+
for (const own of [legacy.get(proto), modern]) {
|
|
255
|
+
if (!own) continue;
|
|
256
|
+
for (const key of Reflect.ownKeys(own)) {
|
|
257
|
+
if (key in result && result[key] !== own[key]) throw new Error(`[mobx-mantle] Cannot change the inherited annotation of ${String(key)}.`);
|
|
258
|
+
result[key] = own[key];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for (const key of Reflect.ownKeys(result)) {
|
|
263
|
+
const own = Object.getOwnPropertyDescriptor(instance, key);
|
|
264
|
+
if (own && "value" in own && isServiceValue(instance, own.value)) throw new Error(`[mobx-mantle] Leave service field ${String(key)} undecorated; its resolver owns observability.`);
|
|
265
|
+
}
|
|
266
|
+
return Reflect.ownKeys(result).length ? result : void 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
71
269
|
// src/behavior.ts
|
|
72
|
-
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
// src/internals.ts
|
|
273
|
+
|
|
274
|
+
function smartBind(fn, context) {
|
|
275
|
+
return function(...args) {
|
|
276
|
+
const globalState = _mobx._getGlobalState.call(void 0, );
|
|
277
|
+
const isInTrackingContext = globalState.trackingDerivation !== null;
|
|
278
|
+
if (isInTrackingContext) {
|
|
279
|
+
return fn.apply(context, args);
|
|
280
|
+
}
|
|
281
|
+
return _mobx.runInAction.call(void 0, () => fn.apply(context, args));
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (process.env.NODE_ENV !== "production") {
|
|
285
|
+
const globalState = _mobx._getGlobalState.call(void 0, );
|
|
286
|
+
if (!globalState || !("trackingDerivation" in globalState)) {
|
|
287
|
+
console.warn(
|
|
288
|
+
"[mobx-mantle] MobX internal state no longer exposes trackingDerivation. smartBind cannot detect tracking contexts and props reads cannot skip self-notification, so method calls may not batch correctly and prop changes may double-render. Check mobx version compatibility."
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function toWatchExpression(source, fireImmediately, ownerName) {
|
|
293
|
+
if (typeof source === "function") {
|
|
294
|
+
return source;
|
|
295
|
+
}
|
|
296
|
+
if (process.env.NODE_ENV !== "production" && !fireImmediately) {
|
|
297
|
+
console.warn(
|
|
298
|
+
`[mobx-mantle] ${ownerName}.watch() received a plain value, which can never change \u2014 the callback will never fire. Pass a getter (() => expr) to watch a live source, or add { fireImmediately: true } if a single immediate call is intended.`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return () => source;
|
|
302
|
+
}
|
|
303
|
+
function registerReactive(host, create) {
|
|
304
|
+
if (host._mounted) {
|
|
305
|
+
return create();
|
|
306
|
+
}
|
|
307
|
+
const spec = { create, stopped: false, dispose: null };
|
|
308
|
+
host._reactiveSpecs.push(spec);
|
|
309
|
+
return () => {
|
|
310
|
+
spec.stopped = true;
|
|
311
|
+
_optionalChain([spec, 'access', _25 => _25.dispose, 'optionalCall', _26 => _26()]);
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function activateSpecs(host) {
|
|
315
|
+
if (host._wasUnmounted) {
|
|
316
|
+
host._wasUnmounted = false;
|
|
317
|
+
for (const spec of host._reactiveSpecs) {
|
|
318
|
+
if (!spec.stopped) {
|
|
319
|
+
spec.dispose = spec.create();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} else if (!host._mounted) {
|
|
323
|
+
for (const spec of host._reactiveSpecs) {
|
|
324
|
+
if (!spec.stopped && spec.dispose === null) {
|
|
325
|
+
spec.dispose = spec.create();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
host._mounted = true;
|
|
330
|
+
}
|
|
331
|
+
function collectProtoInfo(instance, stopProto, excludes, cache) {
|
|
332
|
+
const ctor = instance.constructor;
|
|
333
|
+
const useCache = globalConfig.cacheAnnotations !== false;
|
|
334
|
+
if (useCache) {
|
|
335
|
+
const cached = cache.get(ctor);
|
|
336
|
+
if (cached) return cached;
|
|
337
|
+
}
|
|
338
|
+
const info = { computedKeys: [], methodKeys: [] };
|
|
339
|
+
const seen = /* @__PURE__ */ new Set();
|
|
340
|
+
let proto = Object.getPrototypeOf(instance);
|
|
341
|
+
while (proto && proto !== stopProto && proto !== Object.prototype) {
|
|
342
|
+
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
|
343
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
344
|
+
if (excludes.has(key) || seen.has(key)) continue;
|
|
345
|
+
seen.add(key);
|
|
346
|
+
if (descriptor.get) {
|
|
347
|
+
info.computedKeys.push(key);
|
|
348
|
+
} else if (typeof descriptor.value === "function") {
|
|
349
|
+
info.methodKeys.push(key);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
proto = Object.getPrototypeOf(proto);
|
|
353
|
+
}
|
|
354
|
+
if (useCache) cache.set(ctor, info);
|
|
355
|
+
return info;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/behavior.ts
|
|
359
|
+
var BEHAVIOR_MARKER = /* @__PURE__ */ Symbol.for("mobx-mantle.behavior");
|
|
73
360
|
var BEHAVIOR_EXCLUDES = /* @__PURE__ */ new Set([
|
|
74
361
|
"onCreate",
|
|
75
362
|
"onLayoutMount",
|
|
76
363
|
"onMount",
|
|
77
364
|
"onUnmount",
|
|
365
|
+
"addCleanup",
|
|
366
|
+
"_addCleanup",
|
|
78
367
|
"watch",
|
|
368
|
+
"effect",
|
|
369
|
+
"sync",
|
|
79
370
|
"constructor",
|
|
371
|
+
"inject",
|
|
80
372
|
"_watchDisposers",
|
|
81
|
-
"_disposeWatchers"
|
|
373
|
+
"_disposeWatchers",
|
|
374
|
+
"_reactiveSpecs",
|
|
375
|
+
"_behaviors",
|
|
376
|
+
"_pendingSyncs",
|
|
377
|
+
"_syncWriting",
|
|
378
|
+
"_mounted",
|
|
379
|
+
"_wasUnmounted"
|
|
82
380
|
]);
|
|
381
|
+
var SyncMarker = class {
|
|
382
|
+
constructor(source) {
|
|
383
|
+
this.source = source;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
83
386
|
function isRefLike(value) {
|
|
84
387
|
if (value === null || typeof value !== "object") return false;
|
|
85
388
|
if (Array.isArray(value)) return false;
|
|
@@ -89,16 +392,72 @@ var Behavior = class {
|
|
|
89
392
|
constructor() {
|
|
90
393
|
/** @internal */
|
|
91
394
|
this._watchDisposers = [];
|
|
395
|
+
/** @internal — pre-mount watch/effect registrations, materialized at mount */
|
|
396
|
+
this._reactiveSpecs = [];
|
|
397
|
+
/** @internal — child behaviors declared as fields, collected at construction */
|
|
398
|
+
this._behaviors = [];
|
|
399
|
+
/** @internal — true after the parent Component first mounts */
|
|
400
|
+
this._mounted = false;
|
|
401
|
+
/** @internal — set when effects clean up so StrictMode replay can resurrect pre-mount watchers */
|
|
402
|
+
this._wasUnmounted = false;
|
|
403
|
+
/** @internal — sync() markers awaiting the post-onCreate field scan; null once construction completes */
|
|
404
|
+
this._pendingSyncs = [];
|
|
405
|
+
/** @internal — true while the hidden sync effect writes a mirrored field (dev write-guard) */
|
|
406
|
+
this._syncWriting = false;
|
|
407
|
+
captureServiceScope(this);
|
|
408
|
+
}
|
|
409
|
+
inject(token) {
|
|
410
|
+
return resolveService(this, token);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Register a cleanup function to run automatically on unmount.
|
|
414
|
+
* Returns a function that can be called for early cleanup.
|
|
415
|
+
*
|
|
416
|
+
* Cleanups are one-shot: they are not re-created during React StrictMode's
|
|
417
|
+
* same-instance effect replay. Call this from onMount (which is replayed),
|
|
418
|
+
* or use effect() for a replay-safe setup/teardown pair.
|
|
419
|
+
*/
|
|
420
|
+
addCleanup(cleanup) {
|
|
421
|
+
if (process.env.NODE_ENV !== "production" && !this._mounted) {
|
|
422
|
+
console.warn(
|
|
423
|
+
`[mobx-mantle] ${this.constructor.name}.addCleanup() called before mount. Cleanups are one-shot: they run when mount effects clean up and are not re-created during React StrictMode's same-instance effect replay. Acquire resources in onMount(), or use effect() for a replay-safe setup/teardown pair.`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return this._addCleanup(cleanup);
|
|
427
|
+
}
|
|
428
|
+
/** @internal — addCleanup without the pre-mount dev warning (used by watch/effect) */
|
|
429
|
+
_addCleanup(cleanup) {
|
|
430
|
+
let active = true;
|
|
431
|
+
const dispose = () => {
|
|
432
|
+
if (!active) return;
|
|
433
|
+
active = false;
|
|
434
|
+
try {
|
|
435
|
+
_mobx.runInAction.call(void 0, cleanup);
|
|
436
|
+
} finally {
|
|
437
|
+
const idx = this._watchDisposers.indexOf(dispose);
|
|
438
|
+
if (idx !== -1) this._watchDisposers.splice(idx, 1);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
this._watchDisposers.push(dispose);
|
|
442
|
+
return dispose;
|
|
92
443
|
}
|
|
93
444
|
/**
|
|
94
445
|
* Watch a reactive expression and run a callback when it changes.
|
|
95
|
-
* Automatically disposed on unmount
|
|
96
|
-
*
|
|
97
|
-
*
|
|
446
|
+
* Automatically disposed on unmount and re-created during React StrictMode's
|
|
447
|
+
* same-instance effect replay.
|
|
448
|
+
*
|
|
449
|
+
* Safe to call from onCreate: registration is recorded and comes alive
|
|
450
|
+
* when the parent commits (just before first paint), so the watcher
|
|
451
|
+
* tracks observable fields correctly and renders that React discards
|
|
452
|
+
* never leak reactions.
|
|
453
|
+
*
|
|
454
|
+
* @param source - Reactive expression (getter) to watch, or a MaybeGetter
|
|
455
|
+
* argument passed through as-is. To watch a value that is itself a
|
|
456
|
+
* function, wrap it: `watch(() => this.callback, …)`
|
|
98
457
|
* @param callback - Called when the expression result changes
|
|
99
458
|
* @param options - Optional configuration (delay, fireImmediately)
|
|
100
459
|
* @returns Dispose function for early teardown
|
|
101
|
-
*
|
|
460
|
+
*
|
|
102
461
|
* @example
|
|
103
462
|
* ```tsx
|
|
104
463
|
* onCreate(url: string) {
|
|
@@ -107,36 +466,119 @@ var Behavior = class {
|
|
|
107
466
|
* }
|
|
108
467
|
* ```
|
|
109
468
|
*/
|
|
110
|
-
watch(
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
469
|
+
watch(source, callback, options) {
|
|
470
|
+
const expr = toWatchExpression(source, _optionalChain([options, 'optionalAccess', _27 => _27.fireImmediately]), this.constructor.name);
|
|
471
|
+
return registerReactive(this, () => {
|
|
472
|
+
const dispose = _mobx.reaction.call(void 0,
|
|
473
|
+
expr,
|
|
474
|
+
(value, prevValue) => {
|
|
475
|
+
try {
|
|
476
|
+
callback(value, prevValue);
|
|
477
|
+
} catch (e) {
|
|
478
|
+
reportError(e, { phase: "watch", name: this.constructor.name, isBehavior: true });
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
delay: _optionalChain([options, 'optionalAccess', _28 => _28.delay]),
|
|
483
|
+
fireImmediately: _optionalChain([options, 'optionalAccess', _29 => _29.fireImmediately])
|
|
118
484
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
485
|
+
);
|
|
486
|
+
return this._addCleanup(dispose);
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Run a side effect that auto-tracks reactive dependencies.
|
|
491
|
+
* Re-runs whenever any accessed observable changes.
|
|
492
|
+
* Automatically disposed on unmount.
|
|
493
|
+
*
|
|
494
|
+
* Best for simple synchronization (DOM updates, logging). For complex
|
|
495
|
+
* side effects with explicit triggers, prefer `watch()`.
|
|
496
|
+
*
|
|
497
|
+
* @param fn - Effect function. May return a cleanup function.
|
|
498
|
+
* @param options - Optional configuration (delay)
|
|
499
|
+
* @returns Dispose function for early teardown
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```tsx
|
|
503
|
+
* onCreate() {
|
|
504
|
+
* this.effect(() => {
|
|
505
|
+
* console.log('Current value:', this.value);
|
|
506
|
+
* });
|
|
507
|
+
* }
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
effect(fn, options) {
|
|
511
|
+
return registerReactive(this, () => {
|
|
512
|
+
let cleanup;
|
|
513
|
+
const dispose = _mobx.autorun.call(void 0,
|
|
514
|
+
() => {
|
|
515
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _30 => _30()]));
|
|
516
|
+
cleanup = void 0;
|
|
517
|
+
try {
|
|
518
|
+
const result = fn();
|
|
519
|
+
if (typeof result === "function") {
|
|
520
|
+
cleanup = result;
|
|
521
|
+
}
|
|
522
|
+
} catch (e) {
|
|
523
|
+
reportError(e, { phase: "effect", name: this.constructor.name, isBehavior: true });
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
{ delay: _optionalChain([options, 'optionalAccess', _31 => _31.delay]) }
|
|
527
|
+
);
|
|
528
|
+
return this._addCleanup(() => {
|
|
529
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _32 => _32()]));
|
|
530
|
+
dispose();
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Normalize a MaybeGetter argument into an ordinary field that stays
|
|
536
|
+
* current. Call once in onCreate (or a field initializer) and assign the
|
|
537
|
+
* result to a field; everywhere else, read the field like normal state:
|
|
538
|
+
*
|
|
539
|
+
* ```tsx
|
|
540
|
+
* url!: string;
|
|
541
|
+
*
|
|
542
|
+
* onCreate(url: MaybeGetter<string>) {
|
|
543
|
+
* this.url = this.sync(url); // the one convention line
|
|
544
|
+
* this.watch(() => this.url, (u) => this.load(u));
|
|
545
|
+
* }
|
|
546
|
+
* refresh() { this.load(this.url); } // plain read, always current
|
|
547
|
+
* ```
|
|
548
|
+
*
|
|
549
|
+
* - Plain value → the field just holds it (no effect registered).
|
|
550
|
+
* - Getter → a hidden effect keeps the field updated whenever the getter's
|
|
551
|
+
* observable sources change (alive from mount, like watch/effect).
|
|
552
|
+
*
|
|
553
|
+
* The sync is one-way (argument → field). Don't write to the field from
|
|
554
|
+
* outside: the next source change overwrites it (dev mode warns).
|
|
555
|
+
*/
|
|
556
|
+
sync(source) {
|
|
557
|
+
if (typeof source !== "function") {
|
|
558
|
+
return source;
|
|
559
|
+
}
|
|
560
|
+
if (this._pendingSyncs === null) {
|
|
561
|
+
if (process.env.NODE_ENV !== "production") {
|
|
562
|
+
console.warn(
|
|
563
|
+
`[mobx-mantle] ${this.constructor.name}.sync() called after construction. sync() only works in field initializers or onCreate; returning a one-time snapshot instead. Use watch()/effect() for post-mount reactions.`
|
|
564
|
+
);
|
|
123
565
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (idx !== -1) this._watchDisposers.splice(idx, 1);
|
|
130
|
-
};
|
|
566
|
+
return _chunkWNF647U6cjs.toValue.call(void 0, source);
|
|
567
|
+
}
|
|
568
|
+
const marker = new SyncMarker(source);
|
|
569
|
+
this._pendingSyncs.push(marker);
|
|
570
|
+
return marker;
|
|
131
571
|
}
|
|
132
572
|
/** @internal */
|
|
133
573
|
_disposeWatchers() {
|
|
134
|
-
|
|
574
|
+
const disposers = this._watchDisposers.slice();
|
|
575
|
+
this._watchDisposers.length = 0;
|
|
576
|
+
for (const dispose of disposers) {
|
|
135
577
|
dispose();
|
|
136
578
|
}
|
|
137
|
-
this._watchDisposers.length = 0;
|
|
138
579
|
}
|
|
139
580
|
};
|
|
581
|
+
var behaviorProtoInfo = /* @__PURE__ */ new WeakMap();
|
|
140
582
|
function makeBehaviorObservable(instance) {
|
|
141
583
|
const annotations = {};
|
|
142
584
|
const ownKeys = /* @__PURE__ */ new Set([
|
|
@@ -147,42 +589,117 @@ function makeBehaviorObservable(instance) {
|
|
|
147
589
|
if (BEHAVIOR_EXCLUDES.has(key)) continue;
|
|
148
590
|
if (key in annotations) continue;
|
|
149
591
|
const value = instance[key];
|
|
150
|
-
if (typeof value === "function") continue;
|
|
592
|
+
if (typeof value === "function" || isServiceValue(instance, value)) continue;
|
|
593
|
+
if (isBehavior(value)) {
|
|
594
|
+
annotations[key] = _mobx.observable.ref;
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
151
597
|
if (isRefLike(value)) {
|
|
152
|
-
annotations[key] =
|
|
598
|
+
annotations[key] = _mobx.observable.ref;
|
|
153
599
|
} else {
|
|
154
|
-
annotations[key] =
|
|
600
|
+
annotations[key] = _mobx.observable;
|
|
155
601
|
}
|
|
156
602
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
603
|
+
const protoInfo = collectProtoInfo(instance, Behavior.prototype, BEHAVIOR_EXCLUDES, behaviorProtoInfo);
|
|
604
|
+
for (const key of protoInfo.computedKeys) {
|
|
605
|
+
if (key in annotations) continue;
|
|
606
|
+
annotations[key] = _mobx.computed;
|
|
607
|
+
}
|
|
608
|
+
_mobx.makeObservable.call(void 0, instance, annotations);
|
|
609
|
+
for (const key of protoInfo.methodKeys) {
|
|
610
|
+
if (key in annotations) continue;
|
|
611
|
+
const method = instance[key];
|
|
612
|
+
if (typeof method === "function") {
|
|
613
|
+
instance[key] = smartBind(method, instance);
|
|
168
614
|
}
|
|
169
|
-
proto = Object.getPrototypeOf(proto);
|
|
170
615
|
}
|
|
171
|
-
(0, import_mobx.makeObservable)(instance, annotations);
|
|
172
616
|
}
|
|
173
617
|
function createBehavior(Def, options) {
|
|
174
618
|
var _a, _b, _c;
|
|
175
619
|
const BehaviorClass = (_c = class extends (_b = Def, _a = BEHAVIOR_MARKER, _b) {
|
|
176
620
|
constructor(...args) {
|
|
621
|
+
applyMobxActionPolicy();
|
|
177
622
|
super(...args);
|
|
178
623
|
if (typeof this.onCreate === "function") {
|
|
179
|
-
this.onCreate(...args);
|
|
624
|
+
withOwnerServiceScope(this, () => _mobx.runInAction.call(void 0, () => this.onCreate(...args)));
|
|
180
625
|
}
|
|
181
|
-
const
|
|
182
|
-
|
|
626
|
+
const children = [];
|
|
627
|
+
for (const key of Object.keys(this)) {
|
|
628
|
+
if (key.startsWith("_")) continue;
|
|
629
|
+
const value = this[key];
|
|
630
|
+
if (isBehavior(value) && !isServiceValue(this, value)) {
|
|
631
|
+
children.push({ instance: value });
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
this._behaviors = children;
|
|
635
|
+
const syncedFields = [];
|
|
636
|
+
const pending = _nullishCoalesce(this._pendingSyncs, () => ( null));
|
|
637
|
+
if (Array.isArray(pending) && pending.length > 0) {
|
|
638
|
+
for (const key of Object.keys(this)) {
|
|
639
|
+
const value = this[key];
|
|
640
|
+
if (value instanceof SyncMarker) {
|
|
641
|
+
syncedFields.push({ key, source: value.source });
|
|
642
|
+
this[key] = value.source();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (process.env.NODE_ENV !== "production" && syncedFields.length !== pending.length) {
|
|
646
|
+
console.warn(
|
|
647
|
+
`[mobx-mantle] ${Def.name}: ${pending.length - syncedFields.length} sync() result(s) were not assigned to a field. Assign sync() directly to a field (this.url = this.sync(url)) so Mantle can keep it updated.`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
this._pendingSyncs = null;
|
|
652
|
+
const autoObservable = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _33 => _33.autoObservable]), () => ( globalConfig.autoObservable));
|
|
653
|
+
const annotations = getAnnotations(this);
|
|
654
|
+
if (annotations) {
|
|
655
|
+
_mobx.makeObservable.call(void 0, this, annotations);
|
|
656
|
+
const info = collectProtoInfo(this, Behavior.prototype, BEHAVIOR_EXCLUDES, behaviorProtoInfo);
|
|
657
|
+
for (const key of info.methodKeys) if (!(key in annotations)) this[key] = smartBind(this[key], this);
|
|
658
|
+
} else if (autoObservable) {
|
|
183
659
|
makeBehaviorObservable(this);
|
|
184
660
|
} else {
|
|
185
|
-
(0,
|
|
661
|
+
_mobx.makeObservable.call(void 0, this);
|
|
662
|
+
}
|
|
663
|
+
if (syncedFields.length > 0) {
|
|
664
|
+
const self = this;
|
|
665
|
+
const specs = syncedFields.map(({ key, source }) => ({
|
|
666
|
+
create: () => {
|
|
667
|
+
const dispose = _mobx.autorun.call(void 0, () => {
|
|
668
|
+
try {
|
|
669
|
+
const next = source();
|
|
670
|
+
self._syncWriting = true;
|
|
671
|
+
try {
|
|
672
|
+
_mobx.runInAction.call(void 0, () => {
|
|
673
|
+
self[key] = next;
|
|
674
|
+
});
|
|
675
|
+
} finally {
|
|
676
|
+
self._syncWriting = false;
|
|
677
|
+
}
|
|
678
|
+
} catch (e) {
|
|
679
|
+
reportError(e, { phase: "sync", name: self.constructor.name, isBehavior: true });
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
return self._addCleanup(dispose);
|
|
683
|
+
},
|
|
684
|
+
stopped: false,
|
|
685
|
+
dispose: null
|
|
686
|
+
}));
|
|
687
|
+
self._reactiveSpecs.unshift(...specs);
|
|
688
|
+
if (process.env.NODE_ENV !== "production") {
|
|
689
|
+
for (const { key } of syncedFields) {
|
|
690
|
+
try {
|
|
691
|
+
_mobx.intercept.call(void 0, self, key, (change) => {
|
|
692
|
+
if (!self._syncWriting) {
|
|
693
|
+
console.warn(
|
|
694
|
+
`[mobx-mantle] ${Def.name}.${key} is a one-way synced field (this.sync()). Writing to it from outside will be overwritten by the next source change. Derive with a computed getter, or own the state in a plain field instead.`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
return change;
|
|
698
|
+
});
|
|
699
|
+
} catch (e2) {
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
186
703
|
}
|
|
187
704
|
}
|
|
188
705
|
}, _c[_a] = true, _c);
|
|
@@ -195,35 +712,57 @@ function createBehavior(Def, options) {
|
|
|
195
712
|
}
|
|
196
713
|
function isBehavior(value) {
|
|
197
714
|
if (value === null || typeof value !== "object") return false;
|
|
198
|
-
return value.constructor
|
|
715
|
+
return _optionalChain([value, 'access', _34 => _34.constructor, 'optionalAccess', _35 => _35[BEHAVIOR_MARKER]]) === true;
|
|
199
716
|
}
|
|
200
|
-
function
|
|
717
|
+
function childBehaviors(inst) {
|
|
718
|
+
return Array.isArray(inst._behaviors) ? inst._behaviors : [];
|
|
719
|
+
}
|
|
720
|
+
function layoutMountBehavior(behavior, visited = /* @__PURE__ */ new WeakSet()) {
|
|
201
721
|
const inst = behavior.instance;
|
|
722
|
+
if (visited.has(inst)) return;
|
|
723
|
+
visited.add(inst);
|
|
724
|
+
for (const child of childBehaviors(inst)) {
|
|
725
|
+
layoutMountBehavior(child, visited);
|
|
726
|
+
}
|
|
727
|
+
if (Array.isArray(inst._reactiveSpecs)) {
|
|
728
|
+
activateSpecs(inst);
|
|
729
|
+
} else {
|
|
730
|
+
inst._mounted = true;
|
|
731
|
+
}
|
|
202
732
|
if ("onLayoutMount" in inst && typeof inst.onLayoutMount === "function") {
|
|
203
733
|
try {
|
|
204
|
-
|
|
734
|
+
const result = _mobx.runInAction.call(void 0, () => inst.onLayoutMount());
|
|
735
|
+
behavior.layoutCleanup = typeof result === "function" ? result : void 0;
|
|
205
736
|
} catch (e) {
|
|
206
737
|
reportError(e, { phase: "onLayoutMount", name: inst.constructor.name, isBehavior: true });
|
|
207
738
|
}
|
|
208
739
|
}
|
|
209
740
|
}
|
|
210
|
-
function mountBehavior(behavior) {
|
|
741
|
+
function mountBehavior(behavior, visited = /* @__PURE__ */ new WeakSet()) {
|
|
211
742
|
const inst = behavior.instance;
|
|
743
|
+
if (visited.has(inst)) return;
|
|
744
|
+
visited.add(inst);
|
|
745
|
+
for (const child of childBehaviors(inst)) {
|
|
746
|
+
mountBehavior(child, visited);
|
|
747
|
+
}
|
|
212
748
|
if ("onMount" in inst && typeof inst.onMount === "function") {
|
|
213
749
|
try {
|
|
214
|
-
|
|
750
|
+
const result = _mobx.runInAction.call(void 0, () => inst.onMount());
|
|
751
|
+
behavior.cleanup = typeof result === "function" ? result : void 0;
|
|
215
752
|
} catch (e) {
|
|
216
753
|
reportError(e, { phase: "onMount", name: inst.constructor.name, isBehavior: true });
|
|
217
754
|
}
|
|
218
755
|
}
|
|
219
756
|
}
|
|
220
|
-
function unmountBehavior(behavior) {
|
|
221
|
-
behavior.layoutCleanup?.();
|
|
222
|
-
behavior.cleanup?.();
|
|
757
|
+
function unmountBehavior(behavior, visited = /* @__PURE__ */ new WeakSet()) {
|
|
223
758
|
const inst = behavior.instance;
|
|
759
|
+
if (visited.has(inst)) return;
|
|
760
|
+
visited.add(inst);
|
|
761
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([behavior, 'access', _36 => _36.layoutCleanup, 'optionalCall', _37 => _37()]));
|
|
762
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([behavior, 'access', _38 => _38.cleanup, 'optionalCall', _39 => _39()]));
|
|
224
763
|
if ("onUnmount" in inst && typeof inst.onUnmount === "function") {
|
|
225
764
|
try {
|
|
226
|
-
inst.onUnmount();
|
|
765
|
+
_mobx.runInAction.call(void 0, () => inst.onUnmount());
|
|
227
766
|
} catch (e) {
|
|
228
767
|
reportError(e, { phase: "onUnmount", name: inst.constructor.name, isBehavior: true });
|
|
229
768
|
}
|
|
@@ -231,44 +770,75 @@ function unmountBehavior(behavior) {
|
|
|
231
770
|
if (typeof inst._disposeWatchers === "function") {
|
|
232
771
|
inst._disposeWatchers();
|
|
233
772
|
}
|
|
773
|
+
inst._wasUnmounted = true;
|
|
774
|
+
const children = childBehaviors(inst);
|
|
775
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
776
|
+
unmountBehavior(children[i], visited);
|
|
777
|
+
}
|
|
234
778
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
779
|
+
function warnUncollectedBehaviors(host, hostName, entries, visited = /* @__PURE__ */ new WeakSet()) {
|
|
780
|
+
if (visited.has(host)) return;
|
|
781
|
+
visited.add(host);
|
|
782
|
+
const collected = new Set(entries.map((e) => e.instance));
|
|
783
|
+
for (const key of Object.keys(host)) {
|
|
784
|
+
if (key.startsWith("_")) continue;
|
|
785
|
+
const value = host[key];
|
|
786
|
+
if (isBehavior(value) && !isServiceValue(host, value) && !collected.has(value)) {
|
|
787
|
+
console.warn(
|
|
788
|
+
`[mobx-mantle] ${hostName}.${key} holds a behavior that was assigned after construction, so its lifecycle (onMount, watchers, cleanup) will never run. Create behaviors as class fields so they are collected when the host is constructed.`
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
for (const entry of entries) {
|
|
793
|
+
warnUncollectedBehaviors(
|
|
794
|
+
entry.instance,
|
|
795
|
+
entry.instance.constructor.name,
|
|
796
|
+
childBehaviors(entry.instance),
|
|
797
|
+
visited
|
|
798
|
+
);
|
|
799
|
+
}
|
|
243
800
|
}
|
|
244
|
-
|
|
245
|
-
|
|
801
|
+
|
|
802
|
+
// src/mantle.tsx
|
|
803
|
+
|
|
804
|
+
var componentRefs = /* @__PURE__ */ new WeakSet();
|
|
805
|
+
var ComponentParentContext = _react2.default.createContext(void 0);
|
|
806
|
+
var componentParents = /* @__PURE__ */ new WeakMap();
|
|
807
|
+
var ownerScopes = /* @__PURE__ */ new WeakMap();
|
|
808
|
+
function ownerScope(owner) {
|
|
809
|
+
let scope = ownerScopes.get(owner);
|
|
810
|
+
if (!scope) {
|
|
811
|
+
scope = { handle: { current: owner }, resolver: getServiceResolver(owner), substitutions: void 0 };
|
|
812
|
+
ownerScopes.set(owner, scope);
|
|
813
|
+
}
|
|
814
|
+
return scope;
|
|
246
815
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
};
|
|
250
|
-
observable3.shallow = function(_value, context) {
|
|
251
|
-
setAnnotation(context, mobx.observable.shallow);
|
|
252
|
-
};
|
|
253
|
-
observable3.struct = function(_value, context) {
|
|
254
|
-
setAnnotation(context, mobx.observable.struct);
|
|
255
|
-
};
|
|
256
|
-
observable3.deep = function(_value, context) {
|
|
257
|
-
setAnnotation(context, mobx.observable.deep);
|
|
258
|
-
};
|
|
259
|
-
function action3(_value, context) {
|
|
260
|
-
setAnnotation(context, mobx.action.bound);
|
|
816
|
+
function withRef(props, ref) {
|
|
817
|
+
return ref == null ? props : { ...props, ref };
|
|
261
818
|
}
|
|
262
|
-
|
|
263
|
-
|
|
819
|
+
var activeComponentConstruction;
|
|
820
|
+
function constructComponent(ComponentClass, props, parentHandle) {
|
|
821
|
+
const previousScope = activeComponentConstruction;
|
|
822
|
+
const scope = {
|
|
823
|
+
expectedClass: ComponentClass,
|
|
824
|
+
parentHandle,
|
|
825
|
+
consumed: false
|
|
826
|
+
};
|
|
827
|
+
activeComponentConstruction = scope;
|
|
828
|
+
try {
|
|
829
|
+
return new ComponentClass(props);
|
|
830
|
+
} finally {
|
|
831
|
+
activeComponentConstruction = previousScope;
|
|
832
|
+
}
|
|
264
833
|
}
|
|
265
|
-
function
|
|
266
|
-
const
|
|
267
|
-
|
|
834
|
+
function captureConstructingComponentParent(instance) {
|
|
835
|
+
const scope = activeComponentConstruction;
|
|
836
|
+
if (!scope || scope.consumed || instance.constructor !== scope.expectedClass) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
scope.consumed = true;
|
|
840
|
+
componentParents.set(instance, scope.parentHandle);
|
|
268
841
|
}
|
|
269
|
-
|
|
270
|
-
// src/mantle.tsx
|
|
271
|
-
var viewRefs = /* @__PURE__ */ new WeakSet();
|
|
272
842
|
function shallowEqual(a, b) {
|
|
273
843
|
if (a === b) return true;
|
|
274
844
|
if (!a || !b) return false;
|
|
@@ -280,37 +850,168 @@ function shallowEqual(a, b) {
|
|
|
280
850
|
}
|
|
281
851
|
return true;
|
|
282
852
|
}
|
|
283
|
-
var
|
|
284
|
-
constructor() {
|
|
853
|
+
var PropsBox = class {
|
|
854
|
+
constructor(value, name) {
|
|
855
|
+
/**
|
|
856
|
+
* @internal The owning component's render reaction. Reads coming from it
|
|
857
|
+
* are not tracked: React already re-renders the component on prop change
|
|
858
|
+
* (via memo), so letting the render reaction observe the props atom would
|
|
859
|
+
* only schedule a redundant second render after every prop change.
|
|
860
|
+
* Computeds, watchers, and other components track normally.
|
|
861
|
+
*/
|
|
862
|
+
this._renderReaction = null;
|
|
863
|
+
this._value = value;
|
|
864
|
+
this._atom = _mobx.createAtom.call(void 0, name);
|
|
865
|
+
}
|
|
866
|
+
get() {
|
|
867
|
+
const own = _optionalChain([this, 'access', _40 => _40._renderReaction, 'optionalAccess', _41 => _41.current]);
|
|
868
|
+
if (!own || _mobx._getGlobalState.call(void 0, ).trackingDerivation !== own) {
|
|
869
|
+
this._atom.reportObserved();
|
|
870
|
+
}
|
|
871
|
+
return this._value;
|
|
872
|
+
}
|
|
873
|
+
setSilently(value) {
|
|
874
|
+
this._value = value;
|
|
875
|
+
}
|
|
876
|
+
set(value) {
|
|
877
|
+
this._value = value;
|
|
878
|
+
this._atom.reportChanged();
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
var Component = class {
|
|
882
|
+
constructor(props) {
|
|
285
883
|
/** @internal */
|
|
286
884
|
this._behaviors = [];
|
|
287
885
|
/** @internal */
|
|
288
886
|
this._watchDisposers = [];
|
|
887
|
+
/** @internal — pre-mount watch/effect registrations, materialized at mount */
|
|
888
|
+
this._reactiveSpecs = [];
|
|
889
|
+
/** @internal — true after the first (layout) mount */
|
|
890
|
+
this._mounted = false;
|
|
891
|
+
/** @internal — set when effects clean up so StrictMode replay can resurrect watchers */
|
|
892
|
+
this._wasUnmounted = false;
|
|
893
|
+
this._propsBox = new PropsBox(props, `${this.constructor.name}.props`);
|
|
894
|
+
captureConstructingComponentParent(this);
|
|
895
|
+
captureServiceScope(this);
|
|
289
896
|
}
|
|
290
897
|
get props() {
|
|
291
898
|
return this._propsBox.get();
|
|
292
899
|
}
|
|
293
|
-
/**
|
|
900
|
+
/** Resolve through the scope captured during construction; preserve service identity. */
|
|
901
|
+
inject(token) {
|
|
902
|
+
return resolveService(this, token);
|
|
903
|
+
}
|
|
904
|
+
/** Return the immediate ancestor in the live Mantle view tree. */
|
|
905
|
+
getParent() {
|
|
906
|
+
return _optionalChain([componentParents, 'access', _42 => _42.get, 'call', _43 => _43(this), 'optionalAccess', _44 => _44.current]);
|
|
907
|
+
}
|
|
908
|
+
/** Find the nearest parent with the supplied logical model identity. */
|
|
909
|
+
findParent(type) {
|
|
910
|
+
for (const parent of this.getParents()) {
|
|
911
|
+
if (isModel(parent, type)) return parent;
|
|
912
|
+
}
|
|
913
|
+
return void 0;
|
|
914
|
+
}
|
|
915
|
+
/** Return all Mantle parents, ordered from the immediate parent to the root. */
|
|
916
|
+
getParents() {
|
|
917
|
+
const parents = [];
|
|
918
|
+
let current = this.getParent();
|
|
919
|
+
while (current) {
|
|
920
|
+
parents.push(current);
|
|
921
|
+
current = current.getParent();
|
|
922
|
+
}
|
|
923
|
+
return parents;
|
|
924
|
+
}
|
|
925
|
+
/** Return the highest Mantle ancestor, or this instance when already root. */
|
|
926
|
+
getRoot() {
|
|
927
|
+
const parents = this.getParents();
|
|
928
|
+
return _nullishCoalesce(parents[parents.length - 1], () => ( this));
|
|
929
|
+
}
|
|
930
|
+
/** @internal — called by createComponent to silently update props during render */
|
|
294
931
|
_syncProps(value) {
|
|
295
|
-
this._propsBox.
|
|
932
|
+
this._propsBox.setSilently(value);
|
|
296
933
|
}
|
|
297
934
|
ref() {
|
|
298
935
|
const r = { current: null };
|
|
299
|
-
|
|
936
|
+
componentRefs.add(r);
|
|
300
937
|
return r;
|
|
301
938
|
}
|
|
939
|
+
/**
|
|
940
|
+
* A tracked view of this instance, for handing to code you don't control
|
|
941
|
+
* (a table's row renderer, an error boundary's fallback, a map popup).
|
|
942
|
+
* Created once, so its identity is stable. Re-renders on its own when the
|
|
943
|
+
* state it reads changes. Forwards refs. Carries this model's context, so
|
|
944
|
+
* `findParent()` and services resolve inside it even when a library renders
|
|
945
|
+
* it in its own React root.
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```tsx
|
|
949
|
+
* row = this.view((props: RowProps) => (
|
|
950
|
+
* <tr {...props} className={props.id === this.activeId ? 'active' : ''} />
|
|
951
|
+
* ));
|
|
952
|
+
* ```
|
|
953
|
+
*/
|
|
954
|
+
view(render) {
|
|
955
|
+
const owner = this;
|
|
956
|
+
const name = `${owner.constructor.name}.${render.name || "view"}`;
|
|
957
|
+
const View = _react.forwardRef.call(void 0, (props, ref) => {
|
|
958
|
+
const scope = ownerScope(owner);
|
|
959
|
+
const rendered = useMantleObserver(() => render(withRef(props, ref)), name);
|
|
960
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ComponentParentContext.Provider, { value: scope.handle, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ServiceContext.Provider, { value: scope.resolver, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModelContext.Provider, { value: scope.substitutions, children: rendered }) }) });
|
|
961
|
+
});
|
|
962
|
+
View.displayName = name;
|
|
963
|
+
const Memoized = _react.memo.call(void 0, View);
|
|
964
|
+
trackedComponents.add(Memoized);
|
|
965
|
+
return Memoized;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Register a cleanup function to run automatically on unmount.
|
|
969
|
+
* Returns a function that can be called for early cleanup.
|
|
970
|
+
*
|
|
971
|
+
* Cleanups are one-shot: they are not re-created during React StrictMode's
|
|
972
|
+
* same-instance effect replay. Call this from onMount (which is replayed),
|
|
973
|
+
* or use effect() for a replay-safe setup/teardown pair.
|
|
974
|
+
*/
|
|
975
|
+
addCleanup(cleanup) {
|
|
976
|
+
if (process.env.NODE_ENV !== "production" && !this._mounted) {
|
|
977
|
+
console.warn(
|
|
978
|
+
`[mobx-mantle] ${this.constructor.name}.addCleanup() called before mount. Cleanups are one-shot: they run when mount effects clean up and are not re-created during React StrictMode's same-instance effect replay. Acquire resources in onMount(), or use effect() for a replay-safe setup/teardown pair.`
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
return this._addCleanup(cleanup);
|
|
982
|
+
}
|
|
983
|
+
/** @internal — addCleanup without the pre-mount dev warning (used by watch/effect) */
|
|
984
|
+
_addCleanup(cleanup) {
|
|
985
|
+
let active = true;
|
|
986
|
+
const dispose = () => {
|
|
987
|
+
if (!active) return;
|
|
988
|
+
active = false;
|
|
989
|
+
try {
|
|
990
|
+
_mobx.runInAction.call(void 0, cleanup);
|
|
991
|
+
} finally {
|
|
992
|
+
const idx = this._watchDisposers.indexOf(dispose);
|
|
993
|
+
if (idx !== -1) this._watchDisposers.splice(idx, 1);
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
this._watchDisposers.push(dispose);
|
|
997
|
+
return dispose;
|
|
998
|
+
}
|
|
302
999
|
/**
|
|
303
1000
|
* Watch a reactive expression and run a callback when it changes.
|
|
304
|
-
* Automatically disposed on unmount.
|
|
305
|
-
*
|
|
306
|
-
*
|
|
1001
|
+
* Automatically disposed on unmount. Watchers declared before mount
|
|
1002
|
+
* (field initializers, onCreate) are re-created during React StrictMode's
|
|
1003
|
+
* same-instance effect replay.
|
|
1004
|
+
*
|
|
1005
|
+
* @param source - Reactive expression (getter) to watch, or a MaybeGetter
|
|
1006
|
+
* argument passed through as-is. To watch a value that is itself a
|
|
1007
|
+
* function, wrap it: `watch(() => this.callback, …)`
|
|
307
1008
|
* @param callback - Called when the expression result changes
|
|
308
1009
|
* @param options - Optional configuration (delay, fireImmediately)
|
|
309
1010
|
* @returns Dispose function for early teardown
|
|
310
1011
|
*
|
|
311
1012
|
* @example
|
|
312
1013
|
* ```tsx
|
|
313
|
-
*
|
|
1014
|
+
* onMount() {
|
|
314
1015
|
* this.watch(
|
|
315
1016
|
* () => this.query,
|
|
316
1017
|
* async (query) => {
|
|
@@ -323,41 +1024,98 @@ var View = class {
|
|
|
323
1024
|
* }
|
|
324
1025
|
* ```
|
|
325
1026
|
*/
|
|
326
|
-
watch(
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
1027
|
+
watch(source, callback, options) {
|
|
1028
|
+
const expr = toWatchExpression(source, _optionalChain([options, 'optionalAccess', _45 => _45.fireImmediately]), this.constructor.name);
|
|
1029
|
+
return registerReactive(this, () => {
|
|
1030
|
+
const dispose = _mobx.reaction.call(void 0,
|
|
1031
|
+
expr,
|
|
1032
|
+
(value, prevValue) => {
|
|
1033
|
+
try {
|
|
1034
|
+
callback(value, prevValue);
|
|
1035
|
+
} catch (e) {
|
|
1036
|
+
reportError(e, { phase: "watch", name: this.constructor.name, isBehavior: false });
|
|
1037
|
+
}
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
delay: _optionalChain([options, 'optionalAccess', _46 => _46.delay]),
|
|
1041
|
+
fireImmediately: _optionalChain([options, 'optionalAccess', _47 => _47.fireImmediately])
|
|
334
1042
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
1043
|
+
);
|
|
1044
|
+
return this._addCleanup(dispose);
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Run a side effect that auto-tracks reactive dependencies.
|
|
1049
|
+
* Re-runs whenever any accessed observable changes.
|
|
1050
|
+
* Automatically disposed on unmount. Effects declared before mount
|
|
1051
|
+
* (field initializers, onCreate) are re-created during React StrictMode's
|
|
1052
|
+
* same-instance effect replay.
|
|
1053
|
+
*
|
|
1054
|
+
* Best for simple synchronization (DOM updates, logging). For complex
|
|
1055
|
+
* side effects with explicit triggers, prefer `watch()`.
|
|
1056
|
+
*
|
|
1057
|
+
* @param fn - Effect function. May return a cleanup function.
|
|
1058
|
+
* @param options - Optional configuration (delay)
|
|
1059
|
+
* @returns Dispose function for early teardown
|
|
1060
|
+
*
|
|
1061
|
+
* @example
|
|
1062
|
+
* ```tsx
|
|
1063
|
+
* onMount() {
|
|
1064
|
+
* this.effect(() => {
|
|
1065
|
+
* document.title = `${this.items.length} items`;
|
|
1066
|
+
* });
|
|
1067
|
+
* }
|
|
1068
|
+
* ```
|
|
1069
|
+
*
|
|
1070
|
+
* @example With cleanup
|
|
1071
|
+
* ```tsx
|
|
1072
|
+
* onMount() {
|
|
1073
|
+
* this.effect(() => {
|
|
1074
|
+
* const handler = () => console.log(this.count);
|
|
1075
|
+
* window.addEventListener('click', handler);
|
|
1076
|
+
* return () => window.removeEventListener('click', handler);
|
|
1077
|
+
* });
|
|
1078
|
+
* }
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
effect(fn, options) {
|
|
1082
|
+
return registerReactive(this, () => {
|
|
1083
|
+
let cleanup;
|
|
1084
|
+
const dispose = _mobx.autorun.call(void 0,
|
|
1085
|
+
() => {
|
|
1086
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _48 => _48()]));
|
|
1087
|
+
cleanup = void 0;
|
|
1088
|
+
try {
|
|
1089
|
+
const result = fn();
|
|
1090
|
+
if (typeof result === "function") {
|
|
1091
|
+
cleanup = result;
|
|
1092
|
+
}
|
|
1093
|
+
} catch (e) {
|
|
1094
|
+
reportError(e, { phase: "effect", name: this.constructor.name, isBehavior: false });
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
{ delay: _optionalChain([options, 'optionalAccess', _49 => _49.delay]) }
|
|
1098
|
+
);
|
|
1099
|
+
return this._addCleanup(() => {
|
|
1100
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _50 => _50()]));
|
|
1101
|
+
dispose();
|
|
1102
|
+
});
|
|
1103
|
+
});
|
|
347
1104
|
}
|
|
348
1105
|
/** @internal */
|
|
349
1106
|
_disposeWatchers() {
|
|
350
|
-
|
|
1107
|
+
const disposers = this._watchDisposers.slice();
|
|
1108
|
+
this._watchDisposers.length = 0;
|
|
1109
|
+
for (const dispose of disposers) {
|
|
351
1110
|
dispose();
|
|
352
1111
|
}
|
|
353
|
-
this._watchDisposers.length = 0;
|
|
354
1112
|
}
|
|
355
1113
|
/** @internal - Scan own properties for behavior instances and register them */
|
|
356
1114
|
_collectBehaviors() {
|
|
357
1115
|
for (const key of Object.keys(this)) {
|
|
358
1116
|
if (key.startsWith("_")) continue;
|
|
359
1117
|
const value = this[key];
|
|
360
|
-
if (isBehavior(value)) {
|
|
1118
|
+
if (isBehavior(value) && !isServiceValue(this, value)) {
|
|
361
1119
|
this._behaviors.push({ instance: value });
|
|
362
1120
|
}
|
|
363
1121
|
}
|
|
@@ -383,6 +1141,10 @@ var View = class {
|
|
|
383
1141
|
};
|
|
384
1142
|
var BASE_EXCLUDES = /* @__PURE__ */ new Set([
|
|
385
1143
|
"props",
|
|
1144
|
+
"getParent",
|
|
1145
|
+
"findParent",
|
|
1146
|
+
"getParents",
|
|
1147
|
+
"getRoot",
|
|
386
1148
|
"_propsBox",
|
|
387
1149
|
"forwardRef",
|
|
388
1150
|
"onCreate",
|
|
@@ -392,8 +1154,13 @@ var BASE_EXCLUDES = /* @__PURE__ */ new Set([
|
|
|
392
1154
|
"onUnmount",
|
|
393
1155
|
"render",
|
|
394
1156
|
"ref",
|
|
1157
|
+
"view",
|
|
1158
|
+
"addCleanup",
|
|
1159
|
+
"_addCleanup",
|
|
395
1160
|
"watch",
|
|
1161
|
+
"effect",
|
|
396
1162
|
"constructor",
|
|
1163
|
+
"inject",
|
|
397
1164
|
"_behaviors",
|
|
398
1165
|
"_collectBehaviors",
|
|
399
1166
|
"_layoutMountBehaviors",
|
|
@@ -401,12 +1168,16 @@ var BASE_EXCLUDES = /* @__PURE__ */ new Set([
|
|
|
401
1168
|
"_unmountBehaviors",
|
|
402
1169
|
"_syncProps",
|
|
403
1170
|
"_watchDisposers",
|
|
404
|
-
"_disposeWatchers"
|
|
1171
|
+
"_disposeWatchers",
|
|
1172
|
+
"_reactiveSpecs",
|
|
1173
|
+
"_mounted",
|
|
1174
|
+
"_wasUnmounted"
|
|
405
1175
|
]);
|
|
406
|
-
function
|
|
407
|
-
return value !== null && typeof value === "object" &&
|
|
1176
|
+
function isComponentRef(value) {
|
|
1177
|
+
return value !== null && typeof value === "object" && componentRefs.has(value);
|
|
408
1178
|
}
|
|
409
|
-
|
|
1179
|
+
var componentProtoInfo = /* @__PURE__ */ new WeakMap();
|
|
1180
|
+
function makeComponentObservable(instance, autoBind) {
|
|
410
1181
|
const annotations = {};
|
|
411
1182
|
const ownKeys = /* @__PURE__ */ new Set([
|
|
412
1183
|
...Object.keys(instance),
|
|
@@ -416,71 +1187,98 @@ function makeViewObservable(instance, autoBind) {
|
|
|
416
1187
|
if (BASE_EXCLUDES.has(key)) continue;
|
|
417
1188
|
if (key in annotations) continue;
|
|
418
1189
|
const value = instance[key];
|
|
419
|
-
if (typeof value === "function") continue;
|
|
1190
|
+
if (typeof value === "function" || isServiceValue(instance, value) || trackedComponents.has(value)) continue;
|
|
420
1191
|
if (isBehavior(value)) {
|
|
421
|
-
annotations[key] =
|
|
1192
|
+
annotations[key] = _mobx.observable.ref;
|
|
422
1193
|
continue;
|
|
423
1194
|
}
|
|
424
|
-
if (
|
|
425
|
-
annotations[key] =
|
|
1195
|
+
if (isComponentRef(value)) {
|
|
1196
|
+
annotations[key] = _mobx.observable.ref;
|
|
426
1197
|
} else {
|
|
427
|
-
annotations[key] =
|
|
1198
|
+
annotations[key] = _mobx.observable;
|
|
428
1199
|
}
|
|
429
1200
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
1201
|
+
const protoInfo = collectProtoInfo(instance, Component.prototype, BASE_EXCLUDES, componentProtoInfo);
|
|
1202
|
+
for (const key of protoInfo.computedKeys) {
|
|
1203
|
+
if (key in annotations) continue;
|
|
1204
|
+
annotations[key] = _mobx.computed;
|
|
1205
|
+
}
|
|
1206
|
+
_mobx.makeObservable.call(void 0, instance, annotations);
|
|
1207
|
+
if (autoBind) {
|
|
1208
|
+
for (const key of protoInfo.methodKeys) {
|
|
435
1209
|
if (key in annotations) continue;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
annotations[key] = autoBind ? import_mobx2.action.bound : import_mobx2.action;
|
|
1210
|
+
const method = instance[key];
|
|
1211
|
+
if (typeof method === "function") {
|
|
1212
|
+
instance[key] = smartBind(method, instance);
|
|
440
1213
|
}
|
|
441
1214
|
}
|
|
442
|
-
proto = Object.getPrototypeOf(proto);
|
|
443
1215
|
}
|
|
444
|
-
(0, import_mobx2.makeObservable)(instance, annotations);
|
|
445
1216
|
}
|
|
446
|
-
|
|
1217
|
+
var SubstituteComponent = class extends Component {
|
|
1218
|
+
};
|
|
1219
|
+
function installSubstituteState(instance, state) {
|
|
1220
|
+
const annotations = {};
|
|
1221
|
+
for (const key of Reflect.ownKeys(state)) {
|
|
1222
|
+
if (typeof key !== "string" || key.startsWith("_") || key in instance || BASE_EXCLUDES.has(key)) throw new Error("[mobx-mantle] Substitute state cannot replace framework member " + String(key));
|
|
1223
|
+
const descriptor = Object.getOwnPropertyDescriptor(state, key);
|
|
1224
|
+
if (!("value" in descriptor)) throw new Error("[mobx-mantle] Substitute state must contain data/callbacks, not getters.");
|
|
1225
|
+
Object.defineProperty(instance, key, { value: descriptor.value, enumerable: true, writable: true, configurable: true });
|
|
1226
|
+
annotations[key] = _mobx.observable.ref;
|
|
1227
|
+
}
|
|
1228
|
+
_mobx.makeObservable.call(void 0, instance, annotations);
|
|
1229
|
+
}
|
|
1230
|
+
function createComponent(ComponentClass, templateOrOptions) {
|
|
447
1231
|
const template = typeof templateOrOptions === "function" ? templateOrOptions : void 0;
|
|
448
1232
|
const options = typeof templateOrOptions === "object" ? templateOrOptions : {};
|
|
449
1233
|
const { autoObservable = globalConfig.autoObservable } = options;
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
1234
|
+
const ReactComponent = _react.forwardRef.call(void 0, (props, ref) => {
|
|
1235
|
+
const parentHandle = _react2.default.useContext(ComponentParentContext);
|
|
1236
|
+
const resolver = _react2.default.useContext(ServiceContext);
|
|
1237
|
+
const substitutions = _react2.default.useContext(ModelContext);
|
|
1238
|
+
const substitutedTemplate = _react.useRef.call(void 0, void 0);
|
|
1239
|
+
const vmRef = _react.useRef.call(void 0, null);
|
|
1240
|
+
const componentHandleRef = _react.useRef.call(void 0, null);
|
|
1241
|
+
const classRef = _react.useRef.call(void 0, ComponentClass);
|
|
1242
|
+
const prevPropsRef = _react.useRef.call(void 0, null);
|
|
1243
|
+
const propsNotifyingRef = _react.useRef.call(void 0, false);
|
|
1244
|
+
const renderReactionRef = _react.useRef.call(void 0, { current: null });
|
|
1245
|
+
if (!componentHandleRef.current) {
|
|
1246
|
+
componentHandleRef.current = { current: void 0 };
|
|
1247
|
+
}
|
|
1248
|
+
const componentHandle = componentHandleRef.current;
|
|
1249
|
+
if (vmRef.current && classRef.current !== ComponentClass) {
|
|
1250
|
+
classRef.current = ComponentClass;
|
|
457
1251
|
vmRef.current = null;
|
|
458
1252
|
}
|
|
459
1253
|
if (!vmRef.current) {
|
|
460
|
-
|
|
461
|
-
|
|
1254
|
+
applyMobxActionPolicy();
|
|
1255
|
+
const substitution = _optionalChain([substitutions, 'optionalAccess', _51 => _51.get, 'call', _52 => _52(ComponentClass)]);
|
|
1256
|
+
if (substitution && !substitution.template && !template) throw new Error("[mobx-mantle] A substituted integrated model requires an explicit test template.");
|
|
1257
|
+
const instance = withInjectionScope(resolver, () => substitution ? constructComponent(SubstituteComponent, props, parentHandle) : constructComponent(ComponentClass, props, parentHandle));
|
|
1258
|
+
substitutedTemplate.current = _optionalChain([substitution, 'optionalAccess', _53 => _53.template]);
|
|
1259
|
+
setModelIdentity(instance, ComponentClass);
|
|
1260
|
+
if (substitution) installSubstituteState(instance, substitution.state());
|
|
462
1261
|
instance.forwardRef = ref;
|
|
463
|
-
instance.
|
|
1262
|
+
instance._propsBox._renderReaction = renderReactionRef.current;
|
|
1263
|
+
ownerScopes.set(instance, { handle: componentHandle, resolver: getServiceResolver(instance), substitutions });
|
|
1264
|
+
if (!substitution) instance._collectBehaviors();
|
|
464
1265
|
const decoratorAnnotations = getAnnotations(instance);
|
|
465
|
-
if (
|
|
1266
|
+
if (substitution) {
|
|
1267
|
+
} else if (decoratorAnnotations) {
|
|
466
1268
|
const annotations = { ...decoratorAnnotations };
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
annotations[key] = import_mobx2.action.bound;
|
|
475
|
-
}
|
|
1269
|
+
_mobx.makeObservable.call(void 0, instance, annotations);
|
|
1270
|
+
const protoInfo = collectProtoInfo(instance, Component.prototype, BASE_EXCLUDES, componentProtoInfo);
|
|
1271
|
+
for (const key of protoInfo.methodKeys) {
|
|
1272
|
+
if (key in annotations) continue;
|
|
1273
|
+
const method = instance[key];
|
|
1274
|
+
if (typeof method === "function") {
|
|
1275
|
+
instance[key] = smartBind(method, instance);
|
|
476
1276
|
}
|
|
477
|
-
proto = Object.getPrototypeOf(proto);
|
|
478
1277
|
}
|
|
479
|
-
(0, import_mobx2.makeObservable)(instance, annotations);
|
|
480
1278
|
} else if (autoObservable) {
|
|
481
|
-
|
|
1279
|
+
makeComponentObservable(instance, true);
|
|
482
1280
|
} else {
|
|
483
|
-
(0,
|
|
1281
|
+
_mobx.makeObservable.call(void 0, instance);
|
|
484
1282
|
}
|
|
485
1283
|
const reactiveProps = new Proxy({}, {
|
|
486
1284
|
get: (_, key) => instance.props[key],
|
|
@@ -488,100 +1286,283 @@ function createView(ViewClass, templateOrOptions) {
|
|
|
488
1286
|
ownKeys: () => Reflect.ownKeys(instance.props),
|
|
489
1287
|
getOwnPropertyDescriptor: (_, key) => Reflect.getOwnPropertyDescriptor(instance.props, key)
|
|
490
1288
|
});
|
|
491
|
-
instance.onCreate
|
|
1289
|
+
withOwnerServiceScope(instance, () => _mobx.runInAction.call(void 0, () => _optionalChain([instance, 'access', _54 => _54.onCreate, 'optionalCall', _55 => _55(reactiveProps)])));
|
|
1290
|
+
if (process.env.NODE_ENV !== "production" && autoObservable && !decoratorAnnotations && !substitution) {
|
|
1291
|
+
for (const key of Object.keys(instance)) {
|
|
1292
|
+
if (BASE_EXCLUDES.has(key) || key.startsWith("_")) continue;
|
|
1293
|
+
const value = instance[key];
|
|
1294
|
+
if (typeof value === "function" || isServiceValue(instance, value) || trackedComponents.has(value)) continue;
|
|
1295
|
+
if (!_mobx.isObservableProp.call(void 0, instance, key)) {
|
|
1296
|
+
console.warn(
|
|
1297
|
+
`[mobx-mantle] ${ComponentClass.name}.${key} was first assigned in onCreate() and is not reactive. Declare it as a class field so it can be made observable.`
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
492
1302
|
vmRef.current = instance;
|
|
493
1303
|
prevPropsRef.current = props;
|
|
494
1304
|
}
|
|
495
1305
|
const vm = vmRef.current;
|
|
1306
|
+
const renderTemplate = _nullishCoalesce(substitutedTemplate.current, () => ( template));
|
|
1307
|
+
componentParents.set(vm, parentHandle);
|
|
1308
|
+
componentHandle.current = vm;
|
|
496
1309
|
if (process.env.NODE_ENV !== "production" && propsNotifyingRef.current) {
|
|
497
1310
|
console.warn(
|
|
498
|
-
`[mobx-mantle] ${
|
|
1311
|
+
`[mobx-mantle] ${ComponentClass.name}: A reaction to a prop change modified observable state, which caused an extra re-render. Consider using a computed getter instead.`
|
|
499
1312
|
);
|
|
500
1313
|
propsNotifyingRef.current = false;
|
|
501
1314
|
}
|
|
502
1315
|
vm._syncProps(props);
|
|
503
1316
|
vm.forwardRef = ref;
|
|
504
|
-
(
|
|
1317
|
+
useIsomorphicLayoutEffect(() => {
|
|
505
1318
|
if (!shallowEqual(prevPropsRef.current, props)) {
|
|
506
1319
|
prevPropsRef.current = props;
|
|
507
1320
|
propsNotifyingRef.current = true;
|
|
508
|
-
(0,
|
|
1321
|
+
_mobx.runInAction.call(void 0, () => {
|
|
509
1322
|
vm._propsBox.set(props);
|
|
510
1323
|
});
|
|
511
1324
|
propsNotifyingRef.current = false;
|
|
512
1325
|
}
|
|
513
1326
|
});
|
|
514
|
-
(
|
|
1327
|
+
useIsomorphicLayoutEffect(() => {
|
|
1328
|
+
activateSpecs(vm);
|
|
515
1329
|
vm._layoutMountBehaviors();
|
|
516
1330
|
let cleanup;
|
|
517
1331
|
try {
|
|
518
|
-
const result = vm.onLayoutMount
|
|
1332
|
+
const result = _mobx.runInAction.call(void 0, () => _optionalChain([vm, 'access', _56 => _56.onLayoutMount, 'optionalCall', _57 => _57()]));
|
|
519
1333
|
if (process.env.NODE_ENV !== "production" && result instanceof Promise) {
|
|
520
1334
|
console.error(
|
|
521
|
-
`[mobx-mantle] ${
|
|
1335
|
+
`[mobx-mantle] ${ComponentClass.name}.onLayoutMount() returned a Promise. Lifecycle methods must be synchronous. Use a sync onLayoutMount that calls an async method instead.`
|
|
522
1336
|
);
|
|
523
1337
|
}
|
|
524
|
-
cleanup = result;
|
|
1338
|
+
cleanup = typeof result === "function" ? result : void 0;
|
|
525
1339
|
} catch (e) {
|
|
526
|
-
reportError(e, { phase: "onLayoutMount", name:
|
|
1340
|
+
reportError(e, { phase: "onLayoutMount", name: ComponentClass.name, isBehavior: false });
|
|
527
1341
|
}
|
|
528
1342
|
return () => {
|
|
529
|
-
cleanup
|
|
1343
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _58 => _58()]));
|
|
530
1344
|
};
|
|
531
1345
|
}, [vm]);
|
|
532
|
-
(0,
|
|
1346
|
+
_react.useEffect.call(void 0, () => {
|
|
533
1347
|
vm._mountBehaviors();
|
|
534
1348
|
let cleanup;
|
|
535
1349
|
try {
|
|
536
|
-
const result = vm.onMount
|
|
1350
|
+
const result = _mobx.runInAction.call(void 0, () => _optionalChain([vm, 'access', _59 => _59.onMount, 'optionalCall', _60 => _60()]));
|
|
537
1351
|
if (process.env.NODE_ENV !== "production" && result instanceof Promise) {
|
|
538
1352
|
console.error(
|
|
539
|
-
`[mobx-mantle] ${
|
|
1353
|
+
`[mobx-mantle] ${ComponentClass.name}.onMount() returned a Promise. Lifecycle methods must be synchronous. Use a sync onMount that calls an async method instead.`
|
|
540
1354
|
);
|
|
541
1355
|
}
|
|
542
|
-
cleanup = result;
|
|
1356
|
+
cleanup = typeof result === "function" ? result : void 0;
|
|
543
1357
|
} catch (e) {
|
|
544
|
-
reportError(e, { phase: "onMount", name:
|
|
1358
|
+
reportError(e, { phase: "onMount", name: ComponentClass.name, isBehavior: false });
|
|
1359
|
+
}
|
|
1360
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1361
|
+
warnUncollectedBehaviors(vm, ComponentClass.name, vm._behaviors);
|
|
545
1362
|
}
|
|
546
1363
|
return () => {
|
|
547
|
-
cleanup
|
|
1364
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([cleanup, 'optionalCall', _61 => _61()]));
|
|
548
1365
|
try {
|
|
549
|
-
vm.onUnmount
|
|
1366
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([vm, 'access', _62 => _62.onUnmount, 'optionalCall', _63 => _63()]));
|
|
550
1367
|
} catch (e) {
|
|
551
|
-
reportError(e, { phase: "onUnmount", name:
|
|
1368
|
+
reportError(e, { phase: "onUnmount", name: ComponentClass.name, isBehavior: false });
|
|
552
1369
|
}
|
|
553
1370
|
vm._disposeWatchers();
|
|
554
1371
|
vm._unmountBehaviors();
|
|
1372
|
+
vm._wasUnmounted = true;
|
|
555
1373
|
};
|
|
556
1374
|
}, [vm]);
|
|
557
|
-
(0,
|
|
1375
|
+
_react.useEffect.call(void 0, () => {
|
|
558
1376
|
try {
|
|
559
|
-
vm.onUpdate
|
|
1377
|
+
_mobx.runInAction.call(void 0, () => _optionalChain([vm, 'access', _64 => _64.onUpdate, 'optionalCall', _65 => _65()]));
|
|
560
1378
|
} catch (e) {
|
|
561
|
-
reportError(e, { phase: "onUpdate", name:
|
|
1379
|
+
reportError(e, { phase: "onUpdate", name: ComponentClass.name, isBehavior: false });
|
|
562
1380
|
}
|
|
563
1381
|
});
|
|
564
|
-
if (!
|
|
1382
|
+
if (!renderTemplate && !vm.render) {
|
|
565
1383
|
throw new Error(
|
|
566
|
-
`[mobx-mantle] ${
|
|
1384
|
+
`[mobx-mantle] ${ComponentClass.name}: Missing render() method. Either define render() in your Component class or pass a template function to createComponent().`
|
|
567
1385
|
);
|
|
568
1386
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
1387
|
+
const rendered = useMantleObserver(
|
|
1388
|
+
() => renderTemplate ? renderTemplate(vm) : vm.render(),
|
|
1389
|
+
ComponentClass.name,
|
|
1390
|
+
renderReactionRef.current
|
|
1391
|
+
);
|
|
1392
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ComponentParentContext.Provider, { value: componentHandle, children: rendered });
|
|
572
1393
|
});
|
|
573
|
-
return (0,
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
1394
|
+
return _react.memo.call(void 0, ReactComponent);
|
|
1395
|
+
}
|
|
1396
|
+
function createForwardRef(ComponentClass, templateOrOptions) {
|
|
1397
|
+
return createComponent(ComponentClass, templateOrOptions);
|
|
1398
|
+
}
|
|
1399
|
+
function createView(ModelClass, template) {
|
|
1400
|
+
const name = `${ModelClass.name}.${template.name || "view"}`;
|
|
1401
|
+
const View = _react.forwardRef.call(void 0, (props, ref) => {
|
|
1402
|
+
let vm = _optionalChain([_react.useContext.call(void 0, ComponentParentContext), 'optionalAccess', _66 => _66.current]);
|
|
1403
|
+
while (vm && !isModel(vm, ModelClass)) vm = vm.getParent();
|
|
1404
|
+
if (!vm) {
|
|
1405
|
+
throw new Error(
|
|
1406
|
+
`[mobx-mantle] createView(${ModelClass.name}): no ${ModelClass.name} is mounted above this view.`
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
const model = vm;
|
|
1410
|
+
return useMantleObserver(() => template(withRef({ ...props, vm: model }, ref)), name);
|
|
1411
|
+
});
|
|
1412
|
+
View.displayName = name;
|
|
1413
|
+
const Memoized = _react.memo.call(void 0, View);
|
|
1414
|
+
trackedComponents.add(Memoized);
|
|
1415
|
+
return Memoized;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// src/useBehavior.ts
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
function useBehavior(create) {
|
|
1422
|
+
const resolver = _react.useContext.call(void 0, ServiceContext);
|
|
1423
|
+
const [entry] = _react.useState.call(void 0, () => {
|
|
1424
|
+
const instance = withInjectionScope(resolver, create);
|
|
1425
|
+
if (process.env.NODE_ENV !== "production" && !isBehavior(instance)) {
|
|
1426
|
+
console.warn(
|
|
1427
|
+
"[mobx-mantle] useBehavior() expected the factory to return a behavior instance (created with a factory from createBehavior). Lifecycle relay will be skipped for this value."
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
return { instance };
|
|
1431
|
+
});
|
|
1432
|
+
useIsomorphicLayoutEffect(() => {
|
|
1433
|
+
if (!isBehavior(entry.instance)) return;
|
|
1434
|
+
layoutMountBehavior(entry);
|
|
1435
|
+
}, [entry]);
|
|
1436
|
+
_react.useEffect.call(void 0, () => {
|
|
1437
|
+
if (!isBehavior(entry.instance)) return;
|
|
1438
|
+
mountBehavior(entry);
|
|
1439
|
+
return () => unmountBehavior(entry);
|
|
1440
|
+
}, [entry]);
|
|
1441
|
+
return entry.instance;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// src/shared.ts
|
|
1445
|
+
|
|
1446
|
+
var registry = /* @__PURE__ */ new WeakMap();
|
|
1447
|
+
function ownDataFields(store) {
|
|
1448
|
+
return Object.keys(store).filter((key) => {
|
|
1449
|
+
if (key.startsWith("_")) return false;
|
|
1450
|
+
if (typeof store[key] === "function") return false;
|
|
1451
|
+
return _mobx.isObservableProp.call(void 0, store, key);
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
function serialize(store, fields) {
|
|
1455
|
+
const values = {};
|
|
1456
|
+
for (const field of fields) values[field] = _mobx.toJS.call(void 0, store[field]);
|
|
1457
|
+
return JSON.stringify(values);
|
|
1458
|
+
}
|
|
1459
|
+
function apply(store, fields, json) {
|
|
1460
|
+
let parsed;
|
|
1461
|
+
try {
|
|
1462
|
+
parsed = JSON.parse(json);
|
|
1463
|
+
} catch (e3) {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
1467
|
+
const values = parsed;
|
|
1468
|
+
_mobx.runInAction.call(void 0, () => {
|
|
1469
|
+
for (const field of fields) {
|
|
1470
|
+
if (field in values) store[field] = values[field];
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
return true;
|
|
1474
|
+
}
|
|
1475
|
+
function safeStorage() {
|
|
1476
|
+
try {
|
|
1477
|
+
return typeof localStorage === "undefined" ? null : localStorage;
|
|
1478
|
+
} catch (e4) {
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
function shared(store, key, options = {}) {
|
|
1483
|
+
if (registry.has(store) || typeof window === "undefined") return store;
|
|
1484
|
+
const target = store;
|
|
1485
|
+
const fields = options.fields ? [...options.fields] : ownDataFields(store);
|
|
1486
|
+
const storage = options.persist === false ? null : safeStorage();
|
|
1487
|
+
const channel = typeof BroadcastChannel === "function" ? new BroadcastChannel(`mantle-shared:${key}`) : null;
|
|
1488
|
+
_optionalChain([channel, 'optionalAccess', _67 => _67.unref, 'optionalCall', _68 => _68()]);
|
|
1489
|
+
let stored = null;
|
|
1490
|
+
try {
|
|
1491
|
+
stored = _nullishCoalesce(_optionalChain([storage, 'optionalAccess', _69 => _69.getItem, 'call', _70 => _70(key)]), () => ( null));
|
|
1492
|
+
} catch (e5) {
|
|
1493
|
+
stored = null;
|
|
1494
|
+
}
|
|
1495
|
+
if (stored !== null) apply(target, fields, stored);
|
|
1496
|
+
let current = serialize(target, fields);
|
|
1497
|
+
const stopPublish = _mobx.reaction.call(void 0,
|
|
1498
|
+
() => serialize(target, fields),
|
|
1499
|
+
(json) => {
|
|
1500
|
+
if (json === current) return;
|
|
1501
|
+
current = json;
|
|
1502
|
+
try {
|
|
1503
|
+
_optionalChain([storage, 'optionalAccess', _71 => _71.setItem, 'call', _72 => _72(key, json)]);
|
|
1504
|
+
} catch (e6) {
|
|
1505
|
+
}
|
|
1506
|
+
_optionalChain([channel, 'optionalAccess', _73 => _73.postMessage, 'call', _74 => _74(json)]);
|
|
1507
|
+
}
|
|
1508
|
+
);
|
|
1509
|
+
const receive = (json) => {
|
|
1510
|
+
if (json === current) return;
|
|
1511
|
+
current = json;
|
|
1512
|
+
apply(target, fields, json);
|
|
1513
|
+
};
|
|
1514
|
+
const onMessage = (event) => {
|
|
1515
|
+
if (typeof event.data === "string") receive(event.data);
|
|
1516
|
+
};
|
|
1517
|
+
const onStorage = (event) => {
|
|
1518
|
+
if (event.key === key && event.newValue !== null) receive(event.newValue);
|
|
1519
|
+
};
|
|
1520
|
+
_optionalChain([channel, 'optionalAccess', _75 => _75.addEventListener, 'call', _76 => _76("message", onMessage)]);
|
|
1521
|
+
window.addEventListener("storage", onStorage);
|
|
1522
|
+
registry.set(store, {
|
|
1523
|
+
dispose() {
|
|
1524
|
+
stopPublish();
|
|
1525
|
+
_optionalChain([channel, 'optionalAccess', _77 => _77.removeEventListener, 'call', _78 => _78("message", onMessage)]);
|
|
1526
|
+
_optionalChain([channel, 'optionalAccess', _79 => _79.close, 'call', _80 => _80()]);
|
|
1527
|
+
window.removeEventListener("storage", onStorage);
|
|
1528
|
+
registry.delete(store);
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
return store;
|
|
1532
|
+
}
|
|
1533
|
+
function unshare(store) {
|
|
1534
|
+
_optionalChain([registry, 'access', _81 => _81.get, 'call', _82 => _82(store), 'optionalAccess', _83 => _83.dispose, 'call', _84 => _84()]);
|
|
1535
|
+
}
|
|
1536
|
+
function shareStores(stores, options = {}) {
|
|
1537
|
+
const { prefix = "shared", ...rest } = options;
|
|
1538
|
+
for (const [name, store] of Object.entries(stores)) {
|
|
1539
|
+
shared(store, `${prefix}:${name}`, rest);
|
|
1540
|
+
}
|
|
1541
|
+
return stores;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
|
|
1566
|
+
|
|
1567
|
+
exports.Behavior = Behavior; exports.Component = Component; exports.ModelProvider = ModelProvider; exports.ServiceProvider = ServiceProvider; exports.ViewModel = Component; exports.action = action2; exports.computed = computed2; exports.configure = configure; exports.createBehavior = createBehavior; exports.createComponent = createComponent; exports.createForwardRef = createForwardRef; exports.createServiceToken = createServiceToken; exports.createView = createView; exports.inject = inject; exports.isModel = isModel; exports.observable = observable2; exports.observer = observer; exports.shareStores = shareStores; exports.shared = shared; exports.toValue = _chunkWNF647U6cjs.toValue; exports.unshare = unshare; exports.useBehavior = useBehavior; exports.withInjectionScope = withInjectionScope;
|
|
587
1568
|
//# sourceMappingURL=index.cjs.map
|