chat-layout 1.2.0-8 → 1.2.0-9
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/index.mjs +186 -85
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -3574,31 +3574,13 @@ var DebugRenderer = class extends BaseRenderer {
|
|
|
3574
3574
|
}
|
|
3575
3575
|
};
|
|
3576
3576
|
//#endregion
|
|
3577
|
-
//#region src/renderer/weak-listeners.ts
|
|
3578
|
-
function pruneWeakListenerMap(listeners) {
|
|
3579
|
-
for (const [token, listener] of listeners) if (listener.ownerRef.deref() == null) listeners.delete(token);
|
|
3580
|
-
}
|
|
3581
|
-
function emitWeakListeners(listeners, event) {
|
|
3582
|
-
for (const [token, listener] of [...listeners]) {
|
|
3583
|
-
const owner = listener.ownerRef.deref();
|
|
3584
|
-
if (owner == null) {
|
|
3585
|
-
listeners.delete(token);
|
|
3586
|
-
continue;
|
|
3587
|
-
}
|
|
3588
|
-
listener.notify(owner, event);
|
|
3589
|
-
}
|
|
3590
|
-
}
|
|
3591
|
-
//#endregion
|
|
3592
3577
|
//#region src/renderer/list-state.ts
|
|
3593
|
-
const
|
|
3594
|
-
const listStateListenerRegistry = typeof FinalizationRegistry === "function" ? new FinalizationRegistry(({ listRef, token }) => {
|
|
3595
|
-
const list = listRef.deref();
|
|
3596
|
-
if (list == null) return;
|
|
3597
|
-
deleteListStateListener(list, token);
|
|
3598
|
-
}) : null;
|
|
3578
|
+
const listStateChangeQueues = /* @__PURE__ */ new WeakMap();
|
|
3599
3579
|
const listScrollMutations = /* @__PURE__ */ new WeakMap();
|
|
3600
3580
|
const WRITE_LIST_SCROLL_STATE = Symbol("writeListScrollState");
|
|
3601
3581
|
const FINALIZE_LIST_DELETE = Symbol("finalizeListDelete");
|
|
3582
|
+
const LIST_STATE_CHANGE_TIME = Symbol("listStateChangeTime");
|
|
3583
|
+
const LIST_STATE_CHANGE_SNAPSHOT = Symbol("listStateChangeSnapshot");
|
|
3602
3584
|
function normalizePosition(value) {
|
|
3603
3585
|
return typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : void 0;
|
|
3604
3586
|
}
|
|
@@ -3634,34 +3616,40 @@ function writeInternalListScrollState(list, state) {
|
|
|
3634
3616
|
function finalizeInternalListDelete(list, item) {
|
|
3635
3617
|
list[FINALIZE_LIST_DELETE](item);
|
|
3636
3618
|
}
|
|
3637
|
-
function
|
|
3638
|
-
const listeners = listStateListeners.get(list);
|
|
3639
|
-
if (listeners == null) return;
|
|
3640
|
-
listeners.delete(token);
|
|
3641
|
-
if (listeners.size === 0) listStateListeners.delete(list);
|
|
3642
|
-
}
|
|
3643
|
-
function emitListStateChange(list, change) {
|
|
3644
|
-
const listeners = listStateListeners.get(list);
|
|
3645
|
-
if (listeners == null) return;
|
|
3646
|
-
emitWeakListeners(listeners, change);
|
|
3647
|
-
if (listeners.size === 0) listStateListeners.delete(list);
|
|
3648
|
-
}
|
|
3649
|
-
function subscribeListState(list, owner, listener) {
|
|
3619
|
+
function enqueueListStateChange(list, change) {
|
|
3650
3620
|
const key = list;
|
|
3651
|
-
let
|
|
3652
|
-
if (
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
}
|
|
3656
|
-
const
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3621
|
+
let queue = listStateChangeQueues.get(key);
|
|
3622
|
+
if (queue == null) {
|
|
3623
|
+
queue = [];
|
|
3624
|
+
listStateChangeQueues.set(key, queue);
|
|
3625
|
+
}
|
|
3626
|
+
const timestampedChange = change;
|
|
3627
|
+
Object.defineProperty(timestampedChange, LIST_STATE_CHANGE_TIME, {
|
|
3628
|
+
value: performance.now(),
|
|
3629
|
+
configurable: true
|
|
3660
3630
|
});
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3631
|
+
Object.defineProperty(timestampedChange, LIST_STATE_CHANGE_SNAPSHOT, {
|
|
3632
|
+
value: {
|
|
3633
|
+
items: [...list.items],
|
|
3634
|
+
position: list.position,
|
|
3635
|
+
offset: list.offset
|
|
3636
|
+
},
|
|
3637
|
+
configurable: true
|
|
3664
3638
|
});
|
|
3639
|
+
queue.push(timestampedChange);
|
|
3640
|
+
}
|
|
3641
|
+
function drainInternalListStateChanges(list) {
|
|
3642
|
+
const key = list;
|
|
3643
|
+
const queue = listStateChangeQueues.get(key);
|
|
3644
|
+
if (queue == null || queue.length === 0) return [];
|
|
3645
|
+
listStateChangeQueues.delete(key);
|
|
3646
|
+
return queue;
|
|
3647
|
+
}
|
|
3648
|
+
function readInternalListStateChangeTime(change) {
|
|
3649
|
+
return change[LIST_STATE_CHANGE_TIME];
|
|
3650
|
+
}
|
|
3651
|
+
function readInternalListStateChangeSnapshot(change) {
|
|
3652
|
+
return change[LIST_STATE_CHANGE_SNAPSHOT];
|
|
3665
3653
|
}
|
|
3666
3654
|
function isObjectIdentityCandidate(value) {
|
|
3667
3655
|
return typeof value === "object" && value !== null || typeof value === "function";
|
|
@@ -3724,7 +3712,7 @@ var ListState = class {
|
|
|
3724
3712
|
assertUniqueItemReferences(nextItems);
|
|
3725
3713
|
this.#items = nextItems;
|
|
3726
3714
|
this.#pendingDeletes.clear();
|
|
3727
|
-
|
|
3715
|
+
enqueueListStateChange(this, { type: "set" });
|
|
3728
3716
|
}
|
|
3729
3717
|
/**
|
|
3730
3718
|
* @param items Initial list items.
|
|
@@ -3745,7 +3733,7 @@ var ListState = class {
|
|
|
3745
3733
|
const normalizedAnimation = normalizeInsertAnimation(animation);
|
|
3746
3734
|
if (this.position != null) this.#writeScrollState({ position: this.position + items.length }, "internal");
|
|
3747
3735
|
this.#items = items.concat(this.#items);
|
|
3748
|
-
|
|
3736
|
+
enqueueListStateChange(this, {
|
|
3749
3737
|
type: "unshift",
|
|
3750
3738
|
count: items.length,
|
|
3751
3739
|
animation: normalizedAnimation
|
|
@@ -3761,7 +3749,7 @@ var ListState = class {
|
|
|
3761
3749
|
assertUniqueItemReferences(items, this.#items);
|
|
3762
3750
|
const normalizedAnimation = normalizeInsertAnimation(animation);
|
|
3763
3751
|
this.#items.push(...items);
|
|
3764
|
-
|
|
3752
|
+
enqueueListStateChange(this, {
|
|
3765
3753
|
type: "push",
|
|
3766
3754
|
count: items.length,
|
|
3767
3755
|
animation: normalizedAnimation
|
|
@@ -3779,7 +3767,7 @@ var ListState = class {
|
|
|
3779
3767
|
if (this.#items.includes(nextItem)) throw new Error("update() nextItem is already present in the list.");
|
|
3780
3768
|
const prevItem = this.#items[index];
|
|
3781
3769
|
this.#items[index] = nextItem;
|
|
3782
|
-
|
|
3770
|
+
enqueueListStateChange(this, {
|
|
3783
3771
|
type: "update",
|
|
3784
3772
|
prevItem,
|
|
3785
3773
|
nextItem,
|
|
@@ -3800,7 +3788,7 @@ var ListState = class {
|
|
|
3800
3788
|
return;
|
|
3801
3789
|
}
|
|
3802
3790
|
this.#pendingDeletes.add(item);
|
|
3803
|
-
|
|
3791
|
+
enqueueListStateChange(this, {
|
|
3804
3792
|
type: "delete",
|
|
3805
3793
|
item,
|
|
3806
3794
|
animation: normalizedAnimation
|
|
@@ -3823,7 +3811,7 @@ var ListState = class {
|
|
|
3823
3811
|
if (this.position > index) this.#writeScrollState({ position: this.position - 1 }, "internal");
|
|
3824
3812
|
else if (this.position === index) this.#writeScrollState({ position: Math.min(index, this.#items.length - 1) }, "internal");
|
|
3825
3813
|
}
|
|
3826
|
-
|
|
3814
|
+
enqueueListStateChange(this, {
|
|
3827
3815
|
type: "delete-finalize",
|
|
3828
3816
|
item
|
|
3829
3817
|
});
|
|
@@ -3840,7 +3828,7 @@ var ListState = class {
|
|
|
3840
3828
|
position: void 0,
|
|
3841
3829
|
offset: 0
|
|
3842
3830
|
}, "internal");
|
|
3843
|
-
|
|
3831
|
+
enqueueListStateChange(this, { type: "reset" });
|
|
3844
3832
|
}
|
|
3845
3833
|
/** Applies a relative pixel scroll delta. */
|
|
3846
3834
|
applyScroll(delta) {
|
|
@@ -4046,6 +4034,10 @@ var JumpController = class JumpController {
|
|
|
4046
4034
|
#pendingAutoFollowRecomputeReasonTop = "init";
|
|
4047
4035
|
#pendingAutoFollowRecomputeReasonBottom = "init";
|
|
4048
4036
|
#pendingTransitionSettleReconcile = false;
|
|
4037
|
+
#autoFollowObservationCountTop = 0;
|
|
4038
|
+
#autoFollowObservationCountBottom = 0;
|
|
4039
|
+
#pendingAutoFollowInvalidationTop = false;
|
|
4040
|
+
#pendingAutoFollowInvalidationBottom = false;
|
|
4049
4041
|
#lastArmedAutoFollowBoundary;
|
|
4050
4042
|
#lastObservedRenderedAutoFollowTop = false;
|
|
4051
4043
|
#lastObservedRenderedAutoFollowBottom = false;
|
|
@@ -4127,12 +4119,32 @@ var JumpController = class JumpController {
|
|
|
4127
4119
|
block: boundary === "bottom" ? "end" : "start"
|
|
4128
4120
|
});
|
|
4129
4121
|
}
|
|
4122
|
+
beginAutoFollowBoundaryObservation(boundary) {
|
|
4123
|
+
if (boundary === "top") {
|
|
4124
|
+
this.#autoFollowObservationCountTop += 1;
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
this.#autoFollowObservationCountBottom += 1;
|
|
4128
|
+
}
|
|
4129
|
+
endAutoFollowBoundaryObservation(boundary) {
|
|
4130
|
+
if (boundary === "top") {
|
|
4131
|
+
this.#autoFollowObservationCountTop = Math.max(0, this.#autoFollowObservationCountTop - 1);
|
|
4132
|
+
return;
|
|
4133
|
+
}
|
|
4134
|
+
this.#autoFollowObservationCountBottom = Math.max(0, this.#autoFollowObservationCountBottom - 1);
|
|
4135
|
+
}
|
|
4136
|
+
invalidateAutoFollowBoundary(boundary) {
|
|
4137
|
+
if (boundary == null || boundary === "top") this.#pendingAutoFollowInvalidationTop = true;
|
|
4138
|
+
if (boundary == null || boundary === "bottom") this.#pendingAutoFollowInvalidationBottom = true;
|
|
4139
|
+
}
|
|
4130
4140
|
recomputeAutoFollowCapabilities(capabilities) {
|
|
4131
4141
|
const previouslyObservedDualBoundary = this.#lastObservedRenderedAutoFollowTop && this.#lastObservedRenderedAutoFollowBottom;
|
|
4132
4142
|
if (capabilities.top && capabilities.bottom && !previouslyObservedDualBoundary) {
|
|
4133
4143
|
this.#setAutoFollowBoundary("top", true, "dual-boundary-promotion");
|
|
4134
4144
|
this.#setAutoFollowBoundary("bottom", true, "dual-boundary-promotion");
|
|
4135
4145
|
}
|
|
4146
|
+
this.#syncObservedOrInvalidatedBoundary("top", capabilities);
|
|
4147
|
+
this.#syncObservedOrInvalidatedBoundary("bottom", capabilities);
|
|
4136
4148
|
if (this.#pendingAutoFollowRecomputeTop) {
|
|
4137
4149
|
this.#setAutoFollowBoundary("top", capabilities.top, `strict-recompute:${this.#pendingAutoFollowRecomputeReasonTop}`);
|
|
4138
4150
|
this.#pendingAutoFollowRecomputeTop = false;
|
|
@@ -4159,22 +4171,23 @@ var JumpController = class JumpController {
|
|
|
4159
4171
|
reconcileAutoFollowAfterTransitionSettle() {
|
|
4160
4172
|
this.#pendingTransitionSettleReconcile = true;
|
|
4161
4173
|
}
|
|
4162
|
-
handleListStateChange(change) {
|
|
4174
|
+
handleListStateChange(change, now = getNow()) {
|
|
4163
4175
|
switch (change.type) {
|
|
4164
4176
|
case "reset":
|
|
4165
4177
|
case "set":
|
|
4166
4178
|
this.#cancelJumpAnimation();
|
|
4167
4179
|
this.#clearPendingPostJumpBoundary();
|
|
4168
4180
|
this.#clearPendingTransitionSettleReconcile();
|
|
4181
|
+
this.#clearAutoFollowObservationState();
|
|
4169
4182
|
this.#syncScrollMutationVersion();
|
|
4170
4183
|
this.#markAutoFollowRecompute(void 0, change.type);
|
|
4171
4184
|
return change;
|
|
4172
4185
|
case "push":
|
|
4173
|
-
case "unshift": return this.#handleBoundaryInsert(change);
|
|
4186
|
+
case "unshift": return this.#handleBoundaryInsert(change, now);
|
|
4174
4187
|
default: return change;
|
|
4175
4188
|
}
|
|
4176
4189
|
}
|
|
4177
|
-
#handleBoundaryInsert(change) {
|
|
4190
|
+
#handleBoundaryInsert(change, now) {
|
|
4178
4191
|
if (this.#handlePendingExternalScrollMutation()) return change;
|
|
4179
4192
|
this.#clearPendingTransitionSettleReconcile();
|
|
4180
4193
|
const followChange = this.#resolveAutoFollowChange(change);
|
|
@@ -4187,21 +4200,21 @@ var JumpController = class JumpController {
|
|
|
4187
4200
|
this.#lastArmedAutoFollowBoundary = followChange.boundary;
|
|
4188
4201
|
}
|
|
4189
4202
|
this.#clearPendingPostJumpBoundary();
|
|
4190
|
-
this.#materializeAnimatedAnchor(
|
|
4203
|
+
this.#materializeAnimatedAnchor(now, followChange.direction, followChange.count);
|
|
4191
4204
|
this.#startJumpToIndex(followChange.boundary === "bottom" ? this.#options.getItemCount() - 1 : 0, {
|
|
4192
4205
|
block: followChange.boundary === "bottom" ? "end" : "start",
|
|
4193
4206
|
duration: followChange.animation?.duration
|
|
4194
|
-
});
|
|
4207
|
+
}, now);
|
|
4195
4208
|
return change;
|
|
4196
4209
|
}
|
|
4197
4210
|
#cancelJumpAnimation() {
|
|
4198
4211
|
this.#jumpAnimation = void 0;
|
|
4199
4212
|
}
|
|
4200
|
-
#startJumpToIndex(index, options) {
|
|
4213
|
+
#startJumpToIndex(index, options, now = getNow()) {
|
|
4201
4214
|
const targetIndex = this.#options.clampItemIndex(index);
|
|
4202
4215
|
const targetBlock = options.block ?? this.#options.getDefaultJumpBlock();
|
|
4203
4216
|
const settleBoundary = this.#resolveBoundaryLatchTarget(targetIndex, targetBlock);
|
|
4204
|
-
this.#materializeAnimatedAnchor(
|
|
4217
|
+
this.#materializeAnimatedAnchor(now);
|
|
4205
4218
|
const currentState = this.#options.normalizeListState(this.#options.readListState());
|
|
4206
4219
|
const targetAnchor = this.#options.getTargetAnchor(targetIndex, targetBlock);
|
|
4207
4220
|
if (!(options.animated ?? true)) {
|
|
@@ -4234,7 +4247,7 @@ var JumpController = class JumpController {
|
|
|
4234
4247
|
}
|
|
4235
4248
|
this.#jumpAnimation = {
|
|
4236
4249
|
path,
|
|
4237
|
-
startTime:
|
|
4250
|
+
startTime: now,
|
|
4238
4251
|
duration,
|
|
4239
4252
|
needsMoreFrames: true,
|
|
4240
4253
|
onComplete: options.onComplete
|
|
@@ -4288,6 +4301,12 @@ var JumpController = class JumpController {
|
|
|
4288
4301
|
#clearPendingTransitionSettleReconcile() {
|
|
4289
4302
|
this.#pendingTransitionSettleReconcile = false;
|
|
4290
4303
|
}
|
|
4304
|
+
#clearAutoFollowObservationState() {
|
|
4305
|
+
this.#autoFollowObservationCountTop = 0;
|
|
4306
|
+
this.#autoFollowObservationCountBottom = 0;
|
|
4307
|
+
this.#pendingAutoFollowInvalidationTop = false;
|
|
4308
|
+
this.#pendingAutoFollowInvalidationBottom = false;
|
|
4309
|
+
}
|
|
4291
4310
|
#materializeAnimatedAnchor(now, direction, count = 0) {
|
|
4292
4311
|
const animation = this.#jumpAnimation;
|
|
4293
4312
|
if (animation == null) return;
|
|
@@ -4302,6 +4321,20 @@ var JumpController = class JumpController {
|
|
|
4302
4321
|
if (boundary === "top") this.#canAutoFollowTop = value;
|
|
4303
4322
|
else this.#canAutoFollowBottom = value;
|
|
4304
4323
|
}
|
|
4324
|
+
#syncObservedOrInvalidatedBoundary(boundary, capabilities) {
|
|
4325
|
+
const isObserved = this.#readAutoFollowObservationCount(boundary) > 0;
|
|
4326
|
+
const isInvalidated = boundary === "top" ? this.#pendingAutoFollowInvalidationTop : this.#pendingAutoFollowInvalidationBottom;
|
|
4327
|
+
if (!isObserved && !isInvalidated) return;
|
|
4328
|
+
this.#setAutoFollowBoundary(boundary, this.#readCapabilityForBoundary(capabilities, boundary), "transition-observation");
|
|
4329
|
+
if (boundary === "top") {
|
|
4330
|
+
this.#pendingAutoFollowInvalidationTop = false;
|
|
4331
|
+
return;
|
|
4332
|
+
}
|
|
4333
|
+
this.#pendingAutoFollowInvalidationBottom = false;
|
|
4334
|
+
}
|
|
4335
|
+
#readAutoFollowObservationCount(boundary) {
|
|
4336
|
+
return boundary === "top" ? this.#autoFollowObservationCountTop : this.#autoFollowObservationCountBottom;
|
|
4337
|
+
}
|
|
4305
4338
|
#syncLastArmedBoundaryFromLatchedState() {
|
|
4306
4339
|
if (this.#canAutoFollowTop === this.#canAutoFollowBottom) return;
|
|
4307
4340
|
this.#lastArmedAutoFollowBoundary = this.#canAutoFollowTop ? "top" : "bottom";
|
|
@@ -4815,11 +4848,15 @@ var TransitionStore = class {
|
|
|
4815
4848
|
return this.#transitions.has(item);
|
|
4816
4849
|
}
|
|
4817
4850
|
set(item, transition) {
|
|
4851
|
+
const previous = this.#transitions.get(item);
|
|
4818
4852
|
this.#transitions.set(item, transition);
|
|
4853
|
+
return previous;
|
|
4819
4854
|
}
|
|
4820
4855
|
replace(prevItem, nextItem, transition) {
|
|
4856
|
+
const previous = this.#transitions.get(prevItem);
|
|
4821
4857
|
this.#transitions.delete(prevItem);
|
|
4822
4858
|
this.#transitions.set(nextItem, transition);
|
|
4859
|
+
return previous;
|
|
4823
4860
|
}
|
|
4824
4861
|
delete(item) {
|
|
4825
4862
|
const transition = this.#transitions.get(item);
|
|
@@ -4847,6 +4884,12 @@ var TransitionStore = class {
|
|
|
4847
4884
|
transition
|
|
4848
4885
|
}));
|
|
4849
4886
|
}
|
|
4887
|
+
entries() {
|
|
4888
|
+
return [...this.#transitions.entries()].map(([item, transition]) => ({
|
|
4889
|
+
item,
|
|
4890
|
+
transition
|
|
4891
|
+
}));
|
|
4892
|
+
}
|
|
4850
4893
|
reset() {
|
|
4851
4894
|
this.#transitions.clear();
|
|
4852
4895
|
}
|
|
@@ -4939,6 +4982,30 @@ function planExistingItemTransition(params) {
|
|
|
4939
4982
|
retention: "drawn"
|
|
4940
4983
|
};
|
|
4941
4984
|
}
|
|
4985
|
+
function resolveAutoFollowBoundaryRisk(index, ctx, snapshot) {
|
|
4986
|
+
const drawnRange = snapshot.readDrawnIndexRange();
|
|
4987
|
+
if (index < 0 || !snapshot.hasSnapshot || drawnRange == null || !Number.isFinite(drawnRange.minIndex) || !Number.isFinite(drawnRange.maxIndex)) return;
|
|
4988
|
+
if (ctx.anchorMode === "bottom") return index <= drawnRange.minIndex ? "top" : void 0;
|
|
4989
|
+
return index >= drawnRange.maxIndex ? "bottom" : void 0;
|
|
4990
|
+
}
|
|
4991
|
+
function canClassifyAutoFollowBoundaryRisk(index, snapshot) {
|
|
4992
|
+
return index >= 0 && snapshot.hasSnapshot && snapshot.readDrawnIndexRange() != null;
|
|
4993
|
+
}
|
|
4994
|
+
function beginTransitionAutoFollowObservation(transition, lifecycle) {
|
|
4995
|
+
if (transition.observedAutoFollowBoundary == null) return;
|
|
4996
|
+
lifecycle.beginAutoFollowBoundaryObservation(transition.observedAutoFollowBoundary);
|
|
4997
|
+
}
|
|
4998
|
+
function endTransitionAutoFollowObservation(transition, lifecycle) {
|
|
4999
|
+
if (transition?.observedAutoFollowBoundary == null) return;
|
|
5000
|
+
lifecycle.endAutoFollowBoundaryObservation(transition.observedAutoFollowBoundary);
|
|
5001
|
+
}
|
|
5002
|
+
function invalidateAutoFollowBoundaryRisk(boundary, canClassify, lifecycle) {
|
|
5003
|
+
if (boundary != null) {
|
|
5004
|
+
lifecycle.invalidateAutoFollowBoundary(boundary);
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
if (!canClassify) lifecycle.invalidateAutoFollowBoundary(void 0);
|
|
5008
|
+
}
|
|
4942
5009
|
function planBoundaryInsertItems(params) {
|
|
4943
5010
|
const entries = [];
|
|
4944
5011
|
for (const { item, node, height } of params.measuredItems) {
|
|
@@ -5102,40 +5169,50 @@ function readCurrentVisualState(item, now, store, adapter) {
|
|
|
5102
5169
|
translateY: 0
|
|
5103
5170
|
};
|
|
5104
5171
|
}
|
|
5105
|
-
function handleTransitionStateChange(store, snapshot, change, ctx, lifecycle) {
|
|
5172
|
+
function handleTransitionStateChange(store, snapshot, change, ctx, lifecycle, now = getNow()) {
|
|
5106
5173
|
switch (change.type) {
|
|
5107
5174
|
case "update": {
|
|
5108
|
-
const
|
|
5175
|
+
const nextIndex = ctx.items.indexOf(change.nextItem);
|
|
5176
|
+
const canClassifyRisk = canClassifyAutoFollowBoundaryRisk(nextIndex, snapshot);
|
|
5177
|
+
const observedBoundary = resolveAutoFollowBoundaryRisk(nextIndex, ctx, snapshot);
|
|
5109
5178
|
const currentVisualState = readCurrentVisualState(change.prevItem, now, store, ctx);
|
|
5110
5179
|
const transition = planUpdateTransition(change.prevItem, change.nextItem, change.animation?.duration, now, currentVisualState, ctx, snapshot, store);
|
|
5111
5180
|
if (transition == null) {
|
|
5112
|
-
store.delete(change.prevItem);
|
|
5181
|
+
endTransitionAutoFollowObservation(store.delete(change.prevItem), lifecycle);
|
|
5182
|
+
invalidateAutoFollowBoundaryRisk(observedBoundary, canClassifyRisk, lifecycle);
|
|
5113
5183
|
return;
|
|
5114
5184
|
}
|
|
5115
|
-
|
|
5185
|
+
transition.observedAutoFollowBoundary = observedBoundary;
|
|
5186
|
+
endTransitionAutoFollowObservation(store.replace(change.prevItem, change.nextItem, transition), lifecycle);
|
|
5187
|
+
beginTransitionAutoFollowObservation(transition, lifecycle);
|
|
5116
5188
|
return;
|
|
5117
5189
|
}
|
|
5118
5190
|
case "delete": {
|
|
5119
|
-
const
|
|
5191
|
+
const index = ctx.items.indexOf(change.item);
|
|
5192
|
+
const canClassifyRisk = canClassifyAutoFollowBoundaryRisk(index, snapshot);
|
|
5193
|
+
const observedBoundary = resolveAutoFollowBoundaryRisk(index, ctx, snapshot);
|
|
5120
5194
|
const currentVisualState = readCurrentVisualState(change.item, now, store, ctx);
|
|
5121
5195
|
const transition = planDeleteTransition(change.item, change.animation?.duration, now, currentVisualState, ctx, snapshot, store);
|
|
5122
5196
|
if (transition == null) {
|
|
5123
|
-
store.delete(change.item);
|
|
5197
|
+
endTransitionAutoFollowObservation(store.delete(change.item), lifecycle);
|
|
5198
|
+
invalidateAutoFollowBoundaryRisk(observedBoundary, canClassifyRisk, lifecycle);
|
|
5124
5199
|
lifecycle.onDeleteComplete(change.item);
|
|
5125
5200
|
return;
|
|
5126
5201
|
}
|
|
5127
|
-
|
|
5202
|
+
transition.observedAutoFollowBoundary = observedBoundary;
|
|
5203
|
+
endTransitionAutoFollowObservation(store.set(change.item, transition), lifecycle);
|
|
5204
|
+
beginTransitionAutoFollowObservation(transition, lifecycle);
|
|
5128
5205
|
return;
|
|
5129
5206
|
}
|
|
5130
5207
|
case "delete-finalize":
|
|
5131
|
-
store.delete(change.item);
|
|
5208
|
+
endTransitionAutoFollowObservation(store.delete(change.item), lifecycle);
|
|
5209
|
+
lifecycle.invalidateAutoFollowBoundary(void 0);
|
|
5132
5210
|
return;
|
|
5133
5211
|
case "unshift":
|
|
5134
5212
|
case "push": {
|
|
5135
|
-
const now = getNow();
|
|
5136
5213
|
const plan = planBoundaryInsertTransition(change.type, change.count, change.animation?.duration, now, ctx, snapshot);
|
|
5137
5214
|
if (plan == null) return;
|
|
5138
|
-
for (const entry of plan.entries) store.set(entry.item, entry.transition);
|
|
5215
|
+
for (const entry of plan.entries) endTransitionAutoFollowObservation(store.set(entry.item, entry.transition), lifecycle);
|
|
5139
5216
|
if (ctx.position == null && snapshot.coversShortList && (change.type === "push" && ctx.anchorMode === "bottom" || change.type === "unshift" && ctx.anchorMode === "top")) {
|
|
5140
5217
|
const boundary = change.type === "push" ? "bottom" : "top";
|
|
5141
5218
|
const boundaryItem = snapshot.readBoundaryItem(boundary);
|
|
@@ -5145,6 +5222,7 @@ function handleTransitionStateChange(store, snapshot, change, ctx, lifecycle) {
|
|
|
5145
5222
|
}
|
|
5146
5223
|
case "reset":
|
|
5147
5224
|
case "set":
|
|
5225
|
+
for (const entry of store.entries()) endTransitionAutoFollowObservation(entry.transition, lifecycle);
|
|
5148
5226
|
store.reset();
|
|
5149
5227
|
snapshot.reset();
|
|
5150
5228
|
return;
|
|
@@ -5187,10 +5265,9 @@ var TransitionController = class {
|
|
|
5187
5265
|
resolveItem(item, now, adapter, lifecycle) {
|
|
5188
5266
|
return resolveTransitionedItem(item, now, this.#store, adapter, lifecycle);
|
|
5189
5267
|
}
|
|
5190
|
-
handleListStateChange(change, ctx, lifecycle) {
|
|
5191
|
-
const now = getNow();
|
|
5268
|
+
handleListStateChange(change, ctx, lifecycle, now = getNow()) {
|
|
5192
5269
|
this.settle(now, lifecycle);
|
|
5193
|
-
handleTransitionStateChange(this.#store, this.#snapshot, change, ctx, lifecycle);
|
|
5270
|
+
handleTransitionStateChange(this.#store, this.#snapshot, change, ctx, lifecycle, now);
|
|
5194
5271
|
}
|
|
5195
5272
|
settle(now, lifecycle) {
|
|
5196
5273
|
return this.#settleTransitions(this.#store.findCompleted(now), now, lifecycle);
|
|
@@ -5213,7 +5290,11 @@ var TransitionController = class {
|
|
|
5213
5290
|
const index = lifecycle.readItemIndex(item);
|
|
5214
5291
|
if (index >= 0) completedDeleteIndices.push(index);
|
|
5215
5292
|
}
|
|
5216
|
-
this.#store.delete(item);
|
|
5293
|
+
const removedTransition = this.#store.delete(item);
|
|
5294
|
+
if (removedTransition?.observedAutoFollowBoundary != null) {
|
|
5295
|
+
lifecycle.endAutoFollowBoundaryObservation(removedTransition.observedAutoFollowBoundary);
|
|
5296
|
+
lifecycle.invalidateAutoFollowBoundary(removedTransition.observedAutoFollowBoundary);
|
|
5297
|
+
}
|
|
5217
5298
|
if (transition.kind === "delete") lifecycle.onDeleteComplete(item);
|
|
5218
5299
|
}
|
|
5219
5300
|
if (anchor != null && Number.isFinite(anchor)) lifecycle.restoreVisualAnchor(remapAnchorAfterDeletes(anchor, completedDeleteIndices));
|
|
@@ -5270,6 +5351,7 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5270
5351
|
static JUMP_DURATION_PER_PIXEL = .7;
|
|
5271
5352
|
#jumpController;
|
|
5272
5353
|
#transitionController = new TransitionController();
|
|
5354
|
+
#listStateOverride;
|
|
5273
5355
|
constructor(graphics, options) {
|
|
5274
5356
|
super(graphics, options);
|
|
5275
5357
|
this.#jumpController = new JumpController({
|
|
@@ -5287,21 +5369,18 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5287
5369
|
clampItemIndex: this._clampItemIndex.bind(this),
|
|
5288
5370
|
getItemHeight: this._getItemHeight.bind(this)
|
|
5289
5371
|
});
|
|
5290
|
-
subscribeListState(options.list, this, (owner, change) => {
|
|
5291
|
-
owner.#handleListStateChange(change);
|
|
5292
|
-
});
|
|
5293
5372
|
}
|
|
5294
5373
|
/** Current anchor item index. */
|
|
5295
5374
|
get position() {
|
|
5296
|
-
return this.options.list.position;
|
|
5375
|
+
return this.#listStateOverride?.position ?? this.options.list.position;
|
|
5297
5376
|
}
|
|
5298
5377
|
/** Pixel offset from the anchored item edge. */
|
|
5299
5378
|
get offset() {
|
|
5300
|
-
return this.options.list.offset;
|
|
5379
|
+
return this.#listStateOverride?.offset ?? this.options.list.offset;
|
|
5301
5380
|
}
|
|
5302
5381
|
/** Items currently available to the renderer. */
|
|
5303
5382
|
get items() {
|
|
5304
|
-
return this.options.list.items;
|
|
5383
|
+
return this.#listStateOverride?.items ?? this.options.list.items;
|
|
5305
5384
|
}
|
|
5306
5385
|
/** Replaces the current item collection. */
|
|
5307
5386
|
set items(value) {
|
|
@@ -5309,6 +5388,7 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5309
5388
|
}
|
|
5310
5389
|
/** Renders the current visible window. */
|
|
5311
5390
|
render(feedback) {
|
|
5391
|
+
this.#drainPendingListStateChanges();
|
|
5312
5392
|
this.#jumpController.beforeFrame();
|
|
5313
5393
|
this.#jumpController.noteViewportWidth(this.graphics.canvas.clientWidth);
|
|
5314
5394
|
const now = getNow();
|
|
@@ -5332,6 +5412,7 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5332
5412
|
}
|
|
5333
5413
|
/** Hit-tests the current visible window. */
|
|
5334
5414
|
hittest(test) {
|
|
5415
|
+
this.#drainPendingListStateChanges();
|
|
5335
5416
|
this.#jumpController.beforeFrame();
|
|
5336
5417
|
this.#jumpController.noteViewportWidth(this.graphics.canvas.clientWidth);
|
|
5337
5418
|
const now = getNow();
|
|
@@ -5514,6 +5595,7 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5514
5595
|
}
|
|
5515
5596
|
#handleDeleteComplete(item) {
|
|
5516
5597
|
finalizeInternalListDelete(this.options.list, item);
|
|
5598
|
+
this.#drainPendingListStateChanges();
|
|
5517
5599
|
}
|
|
5518
5600
|
#getTransitionLifecycleAdapter() {
|
|
5519
5601
|
return {
|
|
@@ -5523,7 +5605,10 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5523
5605
|
readScrollState: this._readListState.bind(this),
|
|
5524
5606
|
readItemIndex: (item) => this.items.indexOf(item),
|
|
5525
5607
|
snapItemToViewportBoundary: this.#snapItemToViewportBoundary.bind(this),
|
|
5526
|
-
onTransitionSettleScrollAdjusted: () => this.#jumpController.reconcileAutoFollowAfterTransitionSettle()
|
|
5608
|
+
onTransitionSettleScrollAdjusted: () => this.#jumpController.reconcileAutoFollowAfterTransitionSettle(),
|
|
5609
|
+
beginAutoFollowBoundaryObservation: (boundary) => this.#jumpController.beginAutoFollowBoundaryObservation(boundary),
|
|
5610
|
+
endAutoFollowBoundaryObservation: (boundary) => this.#jumpController.endAutoFollowBoundaryObservation(boundary),
|
|
5611
|
+
invalidateAutoFollowBoundary: (boundary) => this.#jumpController.invalidateAutoFollowBoundary(boundary)
|
|
5527
5612
|
};
|
|
5528
5613
|
}
|
|
5529
5614
|
#getVirtualizedRuntime() {
|
|
@@ -5557,9 +5642,25 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5557
5642
|
anchorMode: this._getLayoutOptions().anchorMode
|
|
5558
5643
|
};
|
|
5559
5644
|
}
|
|
5560
|
-
#handleListStateChange(change) {
|
|
5561
|
-
|
|
5562
|
-
|
|
5645
|
+
#handleListStateChange(change, now = getNow(), snapshot) {
|
|
5646
|
+
this.#listStateOverride = snapshot == null ? void 0 : {
|
|
5647
|
+
items: [...snapshot.items],
|
|
5648
|
+
position: snapshot.position,
|
|
5649
|
+
offset: snapshot.offset
|
|
5650
|
+
};
|
|
5651
|
+
try {
|
|
5652
|
+
const nextChange = this.#jumpController.handleListStateChange(change, now);
|
|
5653
|
+
this.#transitionController.handleListStateChange(nextChange, this.#getTransitionPlanningAdapter(), this.#getTransitionLifecycleAdapter(), now);
|
|
5654
|
+
} finally {
|
|
5655
|
+
this.#listStateOverride = void 0;
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5658
|
+
#drainPendingListStateChanges() {
|
|
5659
|
+
while (true) {
|
|
5660
|
+
const changes = drainInternalListStateChanges(this.options.list);
|
|
5661
|
+
if (changes.length === 0) return;
|
|
5662
|
+
for (const change of changes) this.#handleListStateChange(change, readInternalListStateChangeTime(change), readInternalListStateChangeSnapshot(change));
|
|
5663
|
+
}
|
|
5563
5664
|
}
|
|
5564
5665
|
};
|
|
5565
5666
|
//#endregion
|