@blac/react 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buildTrackedProxy.d.cts +1 -3
- package/dist/buildTrackedProxy.d.ts +1 -3
- package/dist/depSession.d.cts +13 -5
- package/dist/depSession.d.ts +13 -5
- package/dist/index.cjs +252 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +252 -206
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -76,6 +76,44 @@ function collectGetters(proto) {
|
|
|
76
76
|
gettersByProto.set(proto, getters);
|
|
77
77
|
return getters;
|
|
78
78
|
}
|
|
79
|
+
var BlocHandler = class {
|
|
80
|
+
constructor(getters, tracksState, trackedStateRef, onDepHandle) {
|
|
81
|
+
this.getters = getters;
|
|
82
|
+
this.tracksState = tracksState;
|
|
83
|
+
this.trackedStateRef = trackedStateRef;
|
|
84
|
+
this.onDepHandle = onDepHandle;
|
|
85
|
+
this.boundMethods = void 0;
|
|
86
|
+
}
|
|
87
|
+
get(target, key) {
|
|
88
|
+
const getter = this.getters.get(key);
|
|
89
|
+
if (getter !== void 0) {
|
|
90
|
+
const tracked = this.trackedStateRef.current;
|
|
91
|
+
return this.wrapDepHandle(tracked == null || !this.tracksState ? getter.call(target) : target[WITH_TRACKED_STATE](tracked, getter, this.onDepHandle));
|
|
92
|
+
}
|
|
93
|
+
const value = Reflect.get(target, key, target);
|
|
94
|
+
if (typeof value === "function") {
|
|
95
|
+
const fn = value;
|
|
96
|
+
this.boundMethods ??= /* @__PURE__ */ new Map();
|
|
97
|
+
let cached = this.boundMethods.get(key);
|
|
98
|
+
if (cached === void 0 || cached.fn !== fn) {
|
|
99
|
+
cached = {
|
|
100
|
+
fn,
|
|
101
|
+
bound: fn.bind(target)
|
|
102
|
+
};
|
|
103
|
+
this.boundMethods.set(key, cached);
|
|
104
|
+
}
|
|
105
|
+
return this.wrapDepHandle(cached.bound);
|
|
106
|
+
}
|
|
107
|
+
return this.wrapDepHandle(value);
|
|
108
|
+
}
|
|
109
|
+
set(target, key, value) {
|
|
110
|
+
return Reflect.set(target, key, value, target);
|
|
111
|
+
}
|
|
112
|
+
wrapDepHandle(value) {
|
|
113
|
+
if (this.onDepHandle !== void 0 && (typeof value === "function" || typeof value === "object") && value !== null && value[DEP_BRAND] !== void 0) return this.onDepHandle(value);
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
79
117
|
/**
|
|
80
118
|
* Build a per-consumer proxy for a bloc instance.
|
|
81
119
|
*
|
|
@@ -93,68 +131,12 @@ function collectGetters(proto) {
|
|
|
93
131
|
* Must cache wrappers per handle to avoid re-allocation.
|
|
94
132
|
*/
|
|
95
133
|
function buildTrackedProxy(instance, trackedStateRef, onDepHandle) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
const boundMethods = /* @__PURE__ */ new Map();
|
|
99
|
-
const wrapDepHandle = (value) => {
|
|
100
|
-
if (onDepHandle !== void 0 && (typeof value === "function" || typeof value === "object") && value !== null && value[DEP_BRAND] !== void 0) return onDepHandle(value);
|
|
101
|
-
return value;
|
|
102
|
-
};
|
|
103
|
-
return { proxy: new Proxy(instance, {
|
|
104
|
-
get(target, key) {
|
|
105
|
-
const getter = getters.get(key);
|
|
106
|
-
if (getter !== void 0) {
|
|
107
|
-
const tracked = trackedStateRef.current;
|
|
108
|
-
return wrapDepHandle(tracked == null || !tracksState ? getter.call(target) : target[WITH_TRACKED_STATE](tracked, getter, onDepHandle));
|
|
109
|
-
}
|
|
110
|
-
const value = Reflect.get(target, key, target);
|
|
111
|
-
if (typeof value === "function") {
|
|
112
|
-
const fn = value;
|
|
113
|
-
let cached = boundMethods.get(key);
|
|
114
|
-
if (cached === void 0 || cached.fn !== fn) {
|
|
115
|
-
cached = {
|
|
116
|
-
fn,
|
|
117
|
-
bound: fn.bind(target)
|
|
118
|
-
};
|
|
119
|
-
boundMethods.set(key, cached);
|
|
120
|
-
}
|
|
121
|
-
return wrapDepHandle(cached.bound);
|
|
122
|
-
}
|
|
123
|
-
return wrapDepHandle(value);
|
|
124
|
-
},
|
|
125
|
-
set(target, key, value) {
|
|
126
|
-
return Reflect.set(target, key, value, target);
|
|
127
|
-
}
|
|
128
|
-
}) };
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
|
-
//#region src/expandWithAncestors.ts
|
|
132
|
-
/**
|
|
133
|
-
* Add an ancestor-watch id for every ancestor of every tracked leaf, so a
|
|
134
|
-
* `patch` that replaces a parent atomically (e.g. the array `items`) wakes a
|
|
135
|
-
* consumer that read a child (`items.length`).
|
|
136
|
-
*
|
|
137
|
-
* Ancestor-watch ids only match marks the source emits for atomic
|
|
138
|
-
* replacements, never a plain-object pulse-up: `{'user.email'}` does not wake
|
|
139
|
-
* when a sibling `user.name` changes. The `''` root is never added; a root
|
|
140
|
-
* change already marks `ALL_PATHS`.
|
|
141
|
-
*
|
|
142
|
-
* Returns `paths` itself when no leaf has an ancestor.
|
|
143
|
-
*/
|
|
144
|
-
function expandWithAncestors(paths, interner) {
|
|
145
|
-
if (paths === ALL_PATHS) return ALL_PATHS;
|
|
146
|
-
const leafPaths = paths;
|
|
147
|
-
let expanded;
|
|
148
|
-
for (const id of leafPaths) {
|
|
149
|
-
const watch = interner.ancestorWatchIds(id);
|
|
150
|
-
if (watch.length === 0) continue;
|
|
151
|
-
expanded ??= new Set(leafPaths);
|
|
152
|
-
for (let i = 0; i < watch.length; i++) expanded.add(watch[i]);
|
|
153
|
-
}
|
|
154
|
-
return expanded ?? paths;
|
|
134
|
+
const handler = new BlocHandler(collectGetters(Object.getPrototypeOf(instance)), supportsTrackedState(instance), trackedStateRef, onDepHandle);
|
|
135
|
+
return new Proxy(instance, handler);
|
|
155
136
|
}
|
|
156
137
|
//#endregion
|
|
157
138
|
//#region src/depSession.ts
|
|
139
|
+
const NO_PATHS$1 = emptyPathSet();
|
|
158
140
|
/**
|
|
159
141
|
* The containers one `useBloc` consumer reads during a render: its primary
|
|
160
142
|
* bloc plus every dep reached through `this.<handle>.track()`.
|
|
@@ -168,61 +150,91 @@ var DepSession = class {
|
|
|
168
150
|
constructor(consumerId, onChange) {
|
|
169
151
|
this.consumerId = consumerId;
|
|
170
152
|
this.onChange = onChange;
|
|
171
|
-
this.
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
174
|
-
this.
|
|
153
|
+
this.primary = null;
|
|
154
|
+
this.primaryPaths = NO_PATHS$1;
|
|
155
|
+
this.entries = null;
|
|
156
|
+
this.subs = null;
|
|
157
|
+
this.reconciled = false;
|
|
158
|
+
this.lastPrimary = null;
|
|
159
|
+
this.lastPrimaryPaths = NO_PATHS$1;
|
|
160
|
+
this.lastEntries = null;
|
|
161
|
+
this.disarms = null;
|
|
162
|
+
}
|
|
163
|
+
get refId() {
|
|
164
|
+
return `useBloc@${this.consumerId}:dep`;
|
|
175
165
|
}
|
|
176
166
|
begin(primary, paths) {
|
|
177
|
-
this.entries
|
|
178
|
-
this.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
167
|
+
this.entries?.clear();
|
|
168
|
+
if (this.disarms !== null) this.disarms.length = 0;
|
|
169
|
+
this.primary = primary;
|
|
170
|
+
this.primaryPaths = paths;
|
|
182
171
|
}
|
|
183
|
-
record(dep, paths, Type, key, args) {
|
|
184
|
-
|
|
172
|
+
record(dep, paths, Type, key, args, disarm) {
|
|
173
|
+
(this.disarms ??= []).push(disarm);
|
|
174
|
+
if (dep === this.primary) {
|
|
175
|
+
this.primaryPaths = unionPaths(this.primaryPaths, paths);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const entries = this.entries ??= /* @__PURE__ */ new Map();
|
|
179
|
+
const existing = entries.get(dep);
|
|
185
180
|
if (existing !== void 0) existing.paths = unionPaths(existing.paths, paths);
|
|
186
|
-
else
|
|
187
|
-
kind: "dep",
|
|
181
|
+
else entries.set(dep, {
|
|
188
182
|
paths,
|
|
189
183
|
Type,
|
|
190
184
|
key,
|
|
191
185
|
args
|
|
192
186
|
});
|
|
193
187
|
}
|
|
188
|
+
/** Stops every dep tracked this render from recording further reads. */
|
|
189
|
+
disarm() {
|
|
190
|
+
const disarms = this.disarms;
|
|
191
|
+
if (disarms === null) return;
|
|
192
|
+
for (const disarm of disarms) disarm();
|
|
193
|
+
disarms.length = 0;
|
|
194
|
+
}
|
|
194
195
|
/** Forces the next `reconcile` to run in full. */
|
|
195
196
|
invalidate() {
|
|
196
|
-
this.
|
|
197
|
+
this.reconciled = false;
|
|
197
198
|
}
|
|
198
199
|
isUnchanged() {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
if (!this.reconciled || this.lastPrimary !== this.primary || !pathSetEquals(this.lastPrimaryPaths, this.primaryPaths)) return false;
|
|
201
|
+
const last = this.lastEntries;
|
|
202
|
+
const entries = this.entries;
|
|
203
|
+
if ((last?.size ?? 0) !== (entries?.size ?? 0)) return false;
|
|
204
|
+
if (last === null || entries === null) return true;
|
|
205
|
+
for (const [container, entry] of entries) {
|
|
202
206
|
const prev = last.get(container);
|
|
203
207
|
if (prev === void 0 || !sameEntry(prev, entry)) return false;
|
|
204
208
|
}
|
|
205
209
|
return true;
|
|
206
210
|
}
|
|
207
211
|
reconcile(registry) {
|
|
208
|
-
const { consumerId
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
const { consumerId } = this;
|
|
213
|
+
const entries = this.entries;
|
|
214
|
+
this.reconciled = true;
|
|
215
|
+
this.lastPrimary = this.primary;
|
|
216
|
+
this.lastPrimaryPaths = this.primaryPaths;
|
|
217
|
+
this.lastEntries = entries === null || entries.size === 0 ? null : new Map(entries);
|
|
218
|
+
const subs = this.subs;
|
|
219
|
+
if (subs !== null) {
|
|
220
|
+
for (const [dep, sub] of subs) if (entries?.has(dep) !== true) {
|
|
221
|
+
this.drop(dep, sub);
|
|
222
|
+
subs.delete(dep);
|
|
223
|
+
}
|
|
212
224
|
}
|
|
225
|
+
if (entries === null) return;
|
|
213
226
|
for (const [dep, entry] of entries) {
|
|
214
|
-
if (entry.kind === "primary") continue;
|
|
215
227
|
if (dep.$blac.disposed) {
|
|
216
228
|
this.onChange();
|
|
217
229
|
continue;
|
|
218
230
|
}
|
|
219
|
-
const interest = expandWithAncestors(entry.paths, dep.interner);
|
|
220
231
|
dep.registerConsumerPaths(consumerId, entry.paths);
|
|
221
|
-
const existing = subs
|
|
232
|
+
const existing = subs?.get(dep);
|
|
222
233
|
if (existing) {
|
|
223
|
-
existing.
|
|
234
|
+
existing.subscription.setInterest(entry.paths);
|
|
224
235
|
continue;
|
|
225
236
|
}
|
|
237
|
+
const refId = this.refId;
|
|
226
238
|
if (registry.acquire(entry.Type, entry.key, {
|
|
227
239
|
canCreate: true,
|
|
228
240
|
countRef: true,
|
|
@@ -233,33 +245,32 @@ var DepSession = class {
|
|
|
233
245
|
this.onChange();
|
|
234
246
|
continue;
|
|
235
247
|
}
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
subs.set(dep, {
|
|
239
|
-
|
|
240
|
-
interestRef,
|
|
248
|
+
const subscription = dep.subscribePaths(this.onChange);
|
|
249
|
+
subscription.setInterest(entry.paths);
|
|
250
|
+
(this.subs ??= /* @__PURE__ */ new Map()).set(dep, {
|
|
251
|
+
subscription,
|
|
241
252
|
registry,
|
|
242
253
|
Type: entry.Type,
|
|
243
254
|
key: entry.key
|
|
244
255
|
});
|
|
245
256
|
}
|
|
246
|
-
this.lastReconciled = new Map(entries);
|
|
247
257
|
}
|
|
248
258
|
dispose() {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
259
|
+
const subs = this.subs;
|
|
260
|
+
if (subs !== null) {
|
|
261
|
+
for (const [dep, sub] of subs) this.drop(dep, sub);
|
|
262
|
+
subs.clear();
|
|
263
|
+
}
|
|
264
|
+
this.reconciled = false;
|
|
252
265
|
}
|
|
253
266
|
drop(dep, sub) {
|
|
254
|
-
sub.unsubscribe();
|
|
267
|
+
sub.subscription.unsubscribe();
|
|
255
268
|
dep.unregisterConsumer(this.consumerId);
|
|
256
269
|
sub.registry.release(sub.Type, sub.key, false, this.refId);
|
|
257
270
|
}
|
|
258
271
|
};
|
|
259
272
|
function sameEntry(a, b) {
|
|
260
|
-
|
|
261
|
-
if (a.kind === "primary" || b.kind === "primary") return true;
|
|
262
|
-
return a.key === b.key && Object.is(a.args, b.args);
|
|
273
|
+
return pathSetEquals(a.paths, b.paths) && a.key === b.key && Object.is(a.args, b.args);
|
|
263
274
|
}
|
|
264
275
|
function unionPaths(a, b) {
|
|
265
276
|
if (a === ALL_PATHS || b === ALL_PATHS) return ALL_PATHS;
|
|
@@ -305,11 +316,11 @@ function makeDepWrapper(handle, registry, session, tracked, onDepHandle) {
|
|
|
305
316
|
const ref = { current: result.value };
|
|
306
317
|
cache = {
|
|
307
318
|
ref,
|
|
308
|
-
proxy: buildTrackedProxy(dep, ref, onDepHandle)
|
|
319
|
+
proxy: buildTrackedProxy(dep, ref, onDepHandle)
|
|
309
320
|
};
|
|
310
321
|
perDep.set(dep, cache);
|
|
311
322
|
} else cache.ref.current = result.value;
|
|
312
|
-
session.record(dep, result.paths, brand.Type, key, args);
|
|
323
|
+
session.record(dep, result.paths, brand.Type, key, args, result.disarm);
|
|
313
324
|
return [result.value, cache.proxy];
|
|
314
325
|
}
|
|
315
326
|
};
|
|
@@ -378,7 +389,6 @@ function useBloc(BlocClass, options) {
|
|
|
378
389
|
const registry = useRegistry();
|
|
379
390
|
const consumerRef = useRef(null);
|
|
380
391
|
const consumer = consumerRef.current ??= createConsumer();
|
|
381
|
-
const consumerId = consumer.id;
|
|
382
392
|
consumer.select = options?.select;
|
|
383
393
|
consumer.onMount = options?.onMount;
|
|
384
394
|
consumer.onUnmount = options?.onUnmount;
|
|
@@ -386,94 +396,18 @@ function useBloc(BlocClass, options) {
|
|
|
386
396
|
consumer.providerArgs = useProvidedArgs(BlocClass);
|
|
387
397
|
const effectiveArgs = resolveEffectiveArgs(consumer);
|
|
388
398
|
const instanceKey = registry.resolveKey(BlocClass, void 0, effectiveArgs);
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const instance = registry.acquire(BlocClass, instanceKey, {
|
|
392
|
-
canCreate: true,
|
|
393
|
-
countRef: false,
|
|
394
|
-
args: effectiveArgs,
|
|
395
|
-
sweepIfUnowned: true
|
|
396
|
-
});
|
|
397
|
-
const depWrappers = /* @__PURE__ */ new Map();
|
|
398
|
-
const onDepHandle = (handle) => {
|
|
399
|
-
const cached = depWrappers.get(handle);
|
|
400
|
-
if (cached !== void 0) return cached;
|
|
401
|
-
const wrapper = makeDepWrapper(handle, registry, consumer.deps, consumer.tracked, onDepHandle);
|
|
402
|
-
depWrappers.set(handle, wrapper);
|
|
403
|
-
return wrapper;
|
|
404
|
-
};
|
|
405
|
-
const { proxy } = buildTrackedProxy(instance, consumer.tracked, onDepHandle);
|
|
406
|
-
return {
|
|
407
|
-
bloc: instance,
|
|
408
|
-
trackedBloc: proxy
|
|
409
|
-
};
|
|
410
|
-
}, [
|
|
411
|
-
BlocClass,
|
|
412
|
-
instanceKey,
|
|
413
|
-
rebindNonce,
|
|
414
|
-
registry
|
|
415
|
-
]);
|
|
416
|
-
consumer.container = bloc;
|
|
417
|
-
useSyncExternalStore(useMemo(() => (onStoreChange) => {
|
|
418
|
-
consumer.notify = onStoreChange;
|
|
419
|
-
const container = consumer.container;
|
|
420
|
-
const unsubscribe = container.channel.subscribe(() => consumer.interest, () => {
|
|
421
|
-
if (consumer.isSelectMode) {
|
|
422
|
-
const select = consumer.select;
|
|
423
|
-
if (select) {
|
|
424
|
-
const next = select(container.state, container);
|
|
425
|
-
const prev = consumer.selection;
|
|
426
|
-
if (prev !== null && shallowArrayEqual(prev, next)) return;
|
|
427
|
-
consumer.selection = next;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
consumer.bump();
|
|
431
|
-
});
|
|
432
|
-
container.registerConsumerPaths(consumerId, consumer.paths);
|
|
433
|
-
return () => {
|
|
434
|
-
consumer.notify = noop;
|
|
435
|
-
unsubscribe();
|
|
436
|
-
container.unregisterConsumer(consumerId);
|
|
437
|
-
};
|
|
438
|
-
}, [
|
|
439
|
-
BlocClass,
|
|
440
|
-
instanceKey,
|
|
441
|
-
consumerId,
|
|
442
|
-
rebindNonce,
|
|
443
|
-
registry
|
|
444
|
-
]), consumer.getSnapshot, consumer.getServerSnapshot);
|
|
445
|
-
useLayoutEffect(() => {
|
|
446
|
-
const live = registry.acquire(BlocClass, instanceKey, {
|
|
447
|
-
canCreate: true,
|
|
448
|
-
countRef: true,
|
|
449
|
-
refId: consumer.primaryRefId,
|
|
450
|
-
args: resolveEffectiveArgs(consumer)
|
|
451
|
-
});
|
|
452
|
-
consumer.ownedBloc = live;
|
|
453
|
-
consumer.onMount?.(live);
|
|
454
|
-
if (live !== bloc) {
|
|
455
|
-
consumer.rebindNonce++;
|
|
456
|
-
consumer.bump();
|
|
457
|
-
}
|
|
458
|
-
return () => {
|
|
459
|
-
consumer.onUnmount?.(consumer.ownedBloc ?? bloc);
|
|
460
|
-
registry.release(BlocClass, instanceKey, false, consumer.primaryRefId);
|
|
461
|
-
};
|
|
462
|
-
}, [
|
|
463
|
-
BlocClass,
|
|
464
|
-
instanceKey,
|
|
465
|
-
consumerId,
|
|
466
|
-
registry
|
|
467
|
-
]);
|
|
399
|
+
if (consumer.BlocClass !== BlocClass || consumer.instanceKey !== instanceKey || consumer.registry !== registry || consumer.boundNonce !== consumer.rebindNonce) bind(consumer, BlocClass, instanceKey, registry, effectiveArgs);
|
|
400
|
+
useSyncExternalStore(consumer.subscribe, consumer.getSnapshot, consumer.getSnapshot);
|
|
468
401
|
const container = consumer.container;
|
|
469
402
|
const rawState = container.state;
|
|
403
|
+
consumer.renderedState = rawState;
|
|
470
404
|
const select = consumer.select;
|
|
471
405
|
consumer.isSelectMode = select !== void 0;
|
|
472
406
|
let state;
|
|
473
407
|
if (select !== void 0) {
|
|
474
408
|
state = rawState;
|
|
475
|
-
consumer.selection = select(rawState,
|
|
476
|
-
consumer
|
|
409
|
+
consumer.selection = select(rawState, container);
|
|
410
|
+
setInterest(consumer, ALL_PATHS);
|
|
477
411
|
} else {
|
|
478
412
|
const tracked = trackRender(rawState, container.interner, consumer.proxyCache ??= new ProxyCache());
|
|
479
413
|
state = tracked.value;
|
|
@@ -482,34 +416,27 @@ function useBloc(BlocClass, options) {
|
|
|
482
416
|
consumer.disarm = tracked.disarm;
|
|
483
417
|
consumer.deps.begin(container, tracked.paths);
|
|
484
418
|
}
|
|
485
|
-
useLayoutEffect(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (disarm !== null) {
|
|
489
|
-
consumer.disarm = null;
|
|
490
|
-
disarm();
|
|
491
|
-
}
|
|
492
|
-
const deps = consumer.deps;
|
|
493
|
-
if (consumer.isSelectMode) {
|
|
494
|
-
deps.invalidate();
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
if (deps.isUnchanged()) return;
|
|
498
|
-
const primary = consumer.container;
|
|
499
|
-
primary.registerConsumerPaths(consumerId, consumer.paths);
|
|
500
|
-
consumer.interest = expandWithAncestors(consumer.paths, primary.interner);
|
|
501
|
-
deps.reconcile(registry);
|
|
502
|
-
});
|
|
503
|
-
useEffect(() => () => consumer.deps.dispose(), [consumerId]);
|
|
504
|
-
return [state, trackedBloc];
|
|
419
|
+
useLayoutEffect(consumer.commit);
|
|
420
|
+
useLayoutEffect(consumer.mount, NO_DEPS);
|
|
421
|
+
return [state, consumer.trackedBloc];
|
|
505
422
|
}
|
|
506
423
|
const noop = () => {};
|
|
424
|
+
const NO_PATHS = emptyPathSet();
|
|
425
|
+
const NO_DEPS = [];
|
|
507
426
|
function createConsumer() {
|
|
508
427
|
const id = `useBloc-${nextConsumerId++}`;
|
|
509
428
|
const consumer = {
|
|
510
429
|
id,
|
|
511
430
|
primaryRefId: `useBloc@${id}`,
|
|
431
|
+
BlocClass: null,
|
|
432
|
+
instanceKey: "",
|
|
433
|
+
registry: null,
|
|
512
434
|
container: null,
|
|
435
|
+
trackedBloc: null,
|
|
436
|
+
subscribe: null,
|
|
437
|
+
boundNonce: 0,
|
|
438
|
+
rebindNonce: 0,
|
|
439
|
+
renderedState: void 0,
|
|
513
440
|
version: 0,
|
|
514
441
|
notify: noop,
|
|
515
442
|
bump: () => {
|
|
@@ -517,12 +444,17 @@ function createConsumer() {
|
|
|
517
444
|
consumer.notify();
|
|
518
445
|
},
|
|
519
446
|
getSnapshot: () => consumer.version,
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
447
|
+
onChange: () => onChange(consumer),
|
|
448
|
+
unsubscribe: () => unsubscribe(consumer),
|
|
449
|
+
commit: () => commit(consumer),
|
|
450
|
+
mount: () => teardown,
|
|
451
|
+
interest: NO_PATHS,
|
|
452
|
+
subscription: null,
|
|
453
|
+
subscribedTo: null,
|
|
454
|
+
paths: NO_PATHS,
|
|
523
455
|
isSelectMode: false,
|
|
524
456
|
selection: null,
|
|
525
|
-
deps:
|
|
457
|
+
deps: null,
|
|
526
458
|
select: void 0,
|
|
527
459
|
onMount: void 0,
|
|
528
460
|
onUnmount: void 0,
|
|
@@ -531,11 +463,125 @@ function createConsumer() {
|
|
|
531
463
|
tracked: { current: null },
|
|
532
464
|
disarm: null,
|
|
533
465
|
proxyCache: null,
|
|
534
|
-
|
|
466
|
+
ownedClass: null,
|
|
467
|
+
ownedKey: "",
|
|
468
|
+
ownedRegistry: null,
|
|
535
469
|
ownedBloc: null
|
|
536
470
|
};
|
|
471
|
+
const teardown = () => {
|
|
472
|
+
release(consumer);
|
|
473
|
+
consumer.deps.dispose();
|
|
474
|
+
};
|
|
475
|
+
consumer.deps = new DepSession(id, consumer.bump);
|
|
537
476
|
return consumer;
|
|
538
477
|
}
|
|
478
|
+
function bind(consumer, BlocClass, instanceKey, registry, args) {
|
|
479
|
+
const instance = registry.acquire(BlocClass, instanceKey, {
|
|
480
|
+
canCreate: true,
|
|
481
|
+
countRef: false,
|
|
482
|
+
args,
|
|
483
|
+
sweepIfUnowned: true
|
|
484
|
+
});
|
|
485
|
+
let depWrappers;
|
|
486
|
+
const onDepHandle = (handle) => {
|
|
487
|
+
depWrappers ??= /* @__PURE__ */ new Map();
|
|
488
|
+
const cached = depWrappers.get(handle);
|
|
489
|
+
if (cached !== void 0) return cached;
|
|
490
|
+
const wrapper = makeDepWrapper(handle, registry, consumer.deps, consumer.tracked, onDepHandle);
|
|
491
|
+
depWrappers.set(handle, wrapper);
|
|
492
|
+
return wrapper;
|
|
493
|
+
};
|
|
494
|
+
consumer.BlocClass = BlocClass;
|
|
495
|
+
consumer.instanceKey = instanceKey;
|
|
496
|
+
consumer.registry = registry;
|
|
497
|
+
consumer.boundNonce = consumer.rebindNonce;
|
|
498
|
+
consumer.container = instance;
|
|
499
|
+
consumer.trackedBloc = buildTrackedProxy(instance, consumer.tracked, onDepHandle);
|
|
500
|
+
consumer.subscribe = (onStoreChange) => subscribe(consumer, onStoreChange);
|
|
501
|
+
}
|
|
502
|
+
function subscribe(consumer, onStoreChange) {
|
|
503
|
+
consumer.notify = onStoreChange;
|
|
504
|
+
const container = consumer.container;
|
|
505
|
+
const subscription = container.subscribePaths(consumer.onChange);
|
|
506
|
+
subscription.setInterest(consumer.interest);
|
|
507
|
+
consumer.subscription = subscription;
|
|
508
|
+
consumer.subscribedTo = container;
|
|
509
|
+
container.registerConsumerPaths(consumer.id, consumer.paths);
|
|
510
|
+
return consumer.unsubscribe;
|
|
511
|
+
}
|
|
512
|
+
function unsubscribe(consumer) {
|
|
513
|
+
consumer.notify = noop;
|
|
514
|
+
consumer.subscription?.unsubscribe();
|
|
515
|
+
consumer.subscription = null;
|
|
516
|
+
consumer.subscribedTo?.unregisterConsumer(consumer.id);
|
|
517
|
+
consumer.subscribedTo = null;
|
|
518
|
+
}
|
|
519
|
+
function onChange(consumer) {
|
|
520
|
+
if (consumer.isSelectMode) {
|
|
521
|
+
const select = consumer.select;
|
|
522
|
+
const container = consumer.subscribedTo;
|
|
523
|
+
if (select && container !== null) {
|
|
524
|
+
const next = select(container.state, container);
|
|
525
|
+
const prev = consumer.selection;
|
|
526
|
+
if (prev !== null && shallowArrayEqual(prev, next)) return;
|
|
527
|
+
consumer.selection = next;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
consumer.bump();
|
|
531
|
+
}
|
|
532
|
+
function claim(consumer) {
|
|
533
|
+
const { BlocClass, instanceKey, registry } = consumer;
|
|
534
|
+
if (consumer.ownedClass === BlocClass && consumer.ownedKey === instanceKey && consumer.ownedRegistry === registry) return;
|
|
535
|
+
release(consumer);
|
|
536
|
+
const live = registry.acquire(BlocClass, instanceKey, {
|
|
537
|
+
canCreate: true,
|
|
538
|
+
countRef: true,
|
|
539
|
+
refId: consumer.primaryRefId,
|
|
540
|
+
args: resolveEffectiveArgs(consumer)
|
|
541
|
+
});
|
|
542
|
+
consumer.ownedClass = BlocClass;
|
|
543
|
+
consumer.ownedKey = instanceKey;
|
|
544
|
+
consumer.ownedRegistry = registry;
|
|
545
|
+
consumer.ownedBloc = live;
|
|
546
|
+
consumer.onMount?.(live);
|
|
547
|
+
if (live !== consumer.container) {
|
|
548
|
+
consumer.rebindNonce++;
|
|
549
|
+
consumer.bump();
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
function release(consumer) {
|
|
553
|
+
const { ownedClass, ownedRegistry } = consumer;
|
|
554
|
+
if (ownedClass === null || ownedRegistry === null) return;
|
|
555
|
+
consumer.onUnmount?.(consumer.ownedBloc);
|
|
556
|
+
consumer.ownedClass = null;
|
|
557
|
+
consumer.ownedRegistry = null;
|
|
558
|
+
ownedRegistry.release(ownedClass, consumer.ownedKey, false, consumer.primaryRefId);
|
|
559
|
+
}
|
|
560
|
+
function commit(consumer) {
|
|
561
|
+
claim(consumer);
|
|
562
|
+
consumer.tracked.current = null;
|
|
563
|
+
const disarm = consumer.disarm;
|
|
564
|
+
if (disarm !== null) {
|
|
565
|
+
consumer.disarm = null;
|
|
566
|
+
disarm();
|
|
567
|
+
}
|
|
568
|
+
const deps = consumer.deps;
|
|
569
|
+
deps.disarm();
|
|
570
|
+
if (consumer.isSelectMode) {
|
|
571
|
+
deps.invalidate();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
const primary = consumer.container;
|
|
575
|
+
if (primary.state !== consumer.renderedState) consumer.bump();
|
|
576
|
+
if (deps.isUnchanged()) return;
|
|
577
|
+
primary.registerConsumerPaths(consumer.id, consumer.paths);
|
|
578
|
+
setInterest(consumer, consumer.paths);
|
|
579
|
+
deps.reconcile(consumer.registry);
|
|
580
|
+
}
|
|
581
|
+
const setInterest = (consumer, interest) => {
|
|
582
|
+
consumer.interest = interest;
|
|
583
|
+
consumer.subscription?.setInterest(interest);
|
|
584
|
+
};
|
|
539
585
|
const resolveEffectiveArgs = (consumer) => consumer.ownArgs !== void 0 ? consumer.ownArgs : consumer.providerArgs;
|
|
540
586
|
const shallowArrayEqual = (a, b) => {
|
|
541
587
|
if (a === b) return true;
|