chat-layout 1.2.0-4 → 1.2.0-6
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 +24 -1
- package/example/chat.ts +35 -14
- package/index.d.mts +64 -31
- package/index.mjs +1240 -482
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -3649,6 +3649,21 @@ function normalizeUpdateAnimation(animation) {
|
|
|
3649
3649
|
function normalizeDeleteAnimation(animation) {
|
|
3650
3650
|
return normalizeAnimationDuration(animation?.duration);
|
|
3651
3651
|
}
|
|
3652
|
+
const DEFAULT_INSERT_ALL_ANIMATION_DURATION = 220;
|
|
3653
|
+
function normalizeInsertAnimationDuration(duration, hasAnimationOptions) {
|
|
3654
|
+
if (!hasAnimationOptions) return;
|
|
3655
|
+
const resolvedDuration = duration == null ? DEFAULT_INSERT_ALL_ANIMATION_DURATION : duration;
|
|
3656
|
+
if (!Number.isFinite(resolvedDuration) || resolvedDuration <= 0) return;
|
|
3657
|
+
return resolvedDuration;
|
|
3658
|
+
}
|
|
3659
|
+
function normalizeInsertAnimation(animation) {
|
|
3660
|
+
const duration = normalizeInsertAnimationDuration(animation?.duration, animation != null);
|
|
3661
|
+
if (duration == null) return;
|
|
3662
|
+
const normalizedAnimation = { duration };
|
|
3663
|
+
if (typeof animation?.distance === "number" && Number.isFinite(animation.distance)) normalizedAnimation.distance = Math.max(0, animation.distance);
|
|
3664
|
+
if (animation?.autoFollow === true) normalizedAnimation.autoFollow = true;
|
|
3665
|
+
return normalizedAnimation;
|
|
3666
|
+
}
|
|
3652
3667
|
var ListState = class {
|
|
3653
3668
|
#items;
|
|
3654
3669
|
#pendingDeletes = /* @__PURE__ */ new Set();
|
|
@@ -3681,14 +3696,16 @@ var ListState = class {
|
|
|
3681
3696
|
this.unshiftAll(items);
|
|
3682
3697
|
}
|
|
3683
3698
|
/** Prepends an array of items. */
|
|
3684
|
-
unshiftAll(items) {
|
|
3699
|
+
unshiftAll(items, animation) {
|
|
3685
3700
|
if (items.length === 0) return;
|
|
3686
3701
|
assertUniqueItemReferences(items, this.#items);
|
|
3702
|
+
const normalizedAnimation = normalizeInsertAnimation(animation);
|
|
3687
3703
|
if (this.position != null) this.position += items.length;
|
|
3688
3704
|
this.#items = items.concat(this.#items);
|
|
3689
3705
|
emitListStateChange(this, {
|
|
3690
3706
|
type: "unshift",
|
|
3691
|
-
count: items.length
|
|
3707
|
+
count: items.length,
|
|
3708
|
+
animation: normalizedAnimation
|
|
3692
3709
|
});
|
|
3693
3710
|
}
|
|
3694
3711
|
/** Appends one or more items. */
|
|
@@ -3696,13 +3713,15 @@ var ListState = class {
|
|
|
3696
3713
|
this.pushAll(items);
|
|
3697
3714
|
}
|
|
3698
3715
|
/** Appends an array of items. */
|
|
3699
|
-
pushAll(items) {
|
|
3716
|
+
pushAll(items, animation) {
|
|
3700
3717
|
if (items.length === 0) return;
|
|
3701
3718
|
assertUniqueItemReferences(items, this.#items);
|
|
3719
|
+
const normalizedAnimation = normalizeInsertAnimation(animation);
|
|
3702
3720
|
this.#items.push(...items);
|
|
3703
3721
|
emitListStateChange(this, {
|
|
3704
3722
|
type: "push",
|
|
3705
|
-
count: items.length
|
|
3723
|
+
count: items.length,
|
|
3724
|
+
animation: normalizedAnimation
|
|
3706
3725
|
});
|
|
3707
3726
|
}
|
|
3708
3727
|
/**
|
|
@@ -3856,288 +3875,974 @@ function memoRenderItemBy(keyOf, renderItem, options = {}) {
|
|
|
3856
3875
|
}
|
|
3857
3876
|
//#endregion
|
|
3858
3877
|
//#region src/renderer/virtualized/base-animation.ts
|
|
3859
|
-
function clamp$
|
|
3878
|
+
function clamp$1(value, min, max) {
|
|
3860
3879
|
return Math.min(Math.max(value, min), max);
|
|
3861
3880
|
}
|
|
3862
3881
|
function sameState(state, position, offset) {
|
|
3863
3882
|
return Object.is(state.position, position) && Object.is(state.offset, offset);
|
|
3864
3883
|
}
|
|
3884
|
+
function resolveJumpSegmentIndex(anchor, direction, itemCount) {
|
|
3885
|
+
if (itemCount <= 0) return;
|
|
3886
|
+
if (direction > 0) {
|
|
3887
|
+
if (anchor >= itemCount) return;
|
|
3888
|
+
return clamp$1(Math.floor(anchor), 0, itemCount - 1);
|
|
3889
|
+
}
|
|
3890
|
+
if (anchor <= 0) return;
|
|
3891
|
+
return clamp$1(Math.ceil(anchor) - 1, 0, itemCount - 1);
|
|
3892
|
+
}
|
|
3893
|
+
function buildJumpPath(itemCount, readItemHeight, startAnchor, targetAnchor) {
|
|
3894
|
+
const clampedStartAnchor = clamp$1(startAnchor, 0, itemCount);
|
|
3895
|
+
const clampedTargetAnchor = clamp$1(targetAnchor, 0, itemCount);
|
|
3896
|
+
if (itemCount <= 0 || !Number.isFinite(clampedStartAnchor) || !Number.isFinite(clampedTargetAnchor) || Math.abs(clampedTargetAnchor - clampedStartAnchor) <= Number.EPSILON) return {
|
|
3897
|
+
startAnchor: clampedStartAnchor,
|
|
3898
|
+
targetAnchor: clampedTargetAnchor,
|
|
3899
|
+
totalDistance: 0,
|
|
3900
|
+
segments: []
|
|
3901
|
+
};
|
|
3902
|
+
const direction = clampedTargetAnchor > clampedStartAnchor ? 1 : -1;
|
|
3903
|
+
const segments = [];
|
|
3904
|
+
let cursor = clampedStartAnchor;
|
|
3905
|
+
let totalDistance = 0;
|
|
3906
|
+
while (direction > 0 ? cursor < clampedTargetAnchor : cursor > clampedTargetAnchor) {
|
|
3907
|
+
const index = resolveJumpSegmentIndex(cursor, direction, itemCount);
|
|
3908
|
+
if (index == null) break;
|
|
3909
|
+
const nextCursor = direction > 0 ? Math.min(clampedTargetAnchor, index + 1) : Math.max(clampedTargetAnchor, index);
|
|
3910
|
+
if (Math.abs(nextCursor - cursor) <= Number.EPSILON) {
|
|
3911
|
+
cursor = nextCursor;
|
|
3912
|
+
continue;
|
|
3913
|
+
}
|
|
3914
|
+
const height = readItemHeight(index);
|
|
3915
|
+
const distance = height > 0 ? Math.abs(nextCursor - cursor) * height : 0;
|
|
3916
|
+
if (distance > 0) {
|
|
3917
|
+
segments.push({
|
|
3918
|
+
anchorStart: cursor,
|
|
3919
|
+
anchorEnd: nextCursor,
|
|
3920
|
+
distanceStart: totalDistance,
|
|
3921
|
+
distanceEnd: totalDistance + distance
|
|
3922
|
+
});
|
|
3923
|
+
totalDistance += distance;
|
|
3924
|
+
}
|
|
3925
|
+
cursor = nextCursor;
|
|
3926
|
+
}
|
|
3927
|
+
return {
|
|
3928
|
+
startAnchor: clampedStartAnchor,
|
|
3929
|
+
targetAnchor: clampedTargetAnchor,
|
|
3930
|
+
totalDistance,
|
|
3931
|
+
segments
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3865
3934
|
function smoothstep(value) {
|
|
3866
3935
|
return value * value * (3 - 2 * value);
|
|
3867
3936
|
}
|
|
3868
3937
|
function getProgress(startTime, duration, now) {
|
|
3869
3938
|
if (!(duration > 0)) return 1;
|
|
3870
|
-
return clamp$
|
|
3939
|
+
return clamp$1((now - startTime) / duration, 0, 1);
|
|
3871
3940
|
}
|
|
3872
3941
|
function interpolate(from, to, startTime, duration, now) {
|
|
3873
3942
|
const progress = getProgress(startTime, duration, now);
|
|
3874
3943
|
const eased = progress >= 1 ? 1 : smoothstep(progress);
|
|
3875
3944
|
return from + (to - from) * eased;
|
|
3876
3945
|
}
|
|
3946
|
+
function getAnchorAtDistance(path, distance) {
|
|
3947
|
+
if (!(path.totalDistance > 0) || path.segments.length === 0) return path.targetAnchor;
|
|
3948
|
+
const clampedDistance = clamp$1(distance, 0, path.totalDistance);
|
|
3949
|
+
if (clampedDistance <= 0) return path.startAnchor;
|
|
3950
|
+
if (clampedDistance >= path.totalDistance) return path.targetAnchor;
|
|
3951
|
+
for (const segment of path.segments) {
|
|
3952
|
+
if (clampedDistance >= segment.distanceEnd) continue;
|
|
3953
|
+
const span = segment.distanceEnd - segment.distanceStart;
|
|
3954
|
+
if (!(span > 0)) continue;
|
|
3955
|
+
const ratio = (clampedDistance - segment.distanceStart) / span;
|
|
3956
|
+
return segment.anchorStart + (segment.anchorEnd - segment.anchorStart) * ratio;
|
|
3957
|
+
}
|
|
3958
|
+
return path.targetAnchor;
|
|
3959
|
+
}
|
|
3877
3960
|
function getNow() {
|
|
3878
3961
|
return globalThis.performance?.now() ?? Date.now();
|
|
3879
3962
|
}
|
|
3880
3963
|
//#endregion
|
|
3881
|
-
//#region src/renderer/virtualized/
|
|
3882
|
-
|
|
3883
|
-
|
|
3964
|
+
//#region src/renderer/virtualized/frame-session.ts
|
|
3965
|
+
function prepareFrameSession(params) {
|
|
3966
|
+
let solution = params.resolveVisibleWindow(params.now);
|
|
3967
|
+
let viewportTranslateY = params.getViewportTranslateY(params.now);
|
|
3968
|
+
params.captureVisibleItemSnapshot(solution, viewportTranslateY);
|
|
3969
|
+
const requestSettleRedraw = params.pruneTransitionAnimations(solution.window, params.now);
|
|
3970
|
+
if (requestSettleRedraw) {
|
|
3971
|
+
solution = params.resolveVisibleWindow(params.now);
|
|
3972
|
+
viewportTranslateY = params.getViewportTranslateY(params.now);
|
|
3973
|
+
params.captureVisibleItemSnapshot(solution, viewportTranslateY);
|
|
3974
|
+
}
|
|
3975
|
+
return {
|
|
3976
|
+
solution,
|
|
3977
|
+
viewportTranslateY,
|
|
3978
|
+
requestSettleRedraw
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3884
3981
|
//#endregion
|
|
3885
|
-
//#region src/renderer/virtualized/
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
#
|
|
3892
|
-
#
|
|
3893
|
-
#
|
|
3894
|
-
#
|
|
3895
|
-
#
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3982
|
+
//#region src/renderer/virtualized/jump-controller.ts
|
|
3983
|
+
var JumpController = class {
|
|
3984
|
+
#confirmedAutoFollowTop = false;
|
|
3985
|
+
#confirmedAutoFollowBottom = false;
|
|
3986
|
+
#controlledState;
|
|
3987
|
+
#jumpAnimation;
|
|
3988
|
+
#lastCommittedState;
|
|
3989
|
+
#hasPendingListChange = false;
|
|
3990
|
+
#pendingBoundaryJumpTop = false;
|
|
3991
|
+
#pendingBoundaryJumpBottom = false;
|
|
3992
|
+
#options;
|
|
3993
|
+
constructor(options) {
|
|
3994
|
+
this.#options = options;
|
|
3995
|
+
}
|
|
3996
|
+
beforeFrame() {
|
|
3997
|
+
const currentState = this.#options.readListState();
|
|
3998
|
+
if (!this.#hasPendingListChange && this.#jumpAnimation == null && this.#lastCommittedState != null && !sameState(this.#lastCommittedState, currentState.position, currentState.offset)) this.#clearPendingBoundaryJumps();
|
|
3999
|
+
this.#hasPendingListChange = false;
|
|
4000
|
+
}
|
|
4001
|
+
prepare(now) {
|
|
4002
|
+
const animation = this.#jumpAnimation;
|
|
4003
|
+
if (animation == null) return false;
|
|
4004
|
+
if (this.#options.getItemCount() === 0) {
|
|
4005
|
+
this.#cancelJumpAnimation();
|
|
4006
|
+
return false;
|
|
3902
4007
|
}
|
|
3903
|
-
this.#
|
|
3904
|
-
|
|
3905
|
-
|
|
4008
|
+
if (this.#controlledState != null && !sameState(this.#controlledState, this.#options.readListState().position, this.#options.readListState().offset)) {
|
|
4009
|
+
this.#clearPendingBoundaryJumps();
|
|
4010
|
+
this.#cancelJumpAnimation();
|
|
4011
|
+
return false;
|
|
4012
|
+
}
|
|
4013
|
+
const progress = getProgress(animation.startTime, animation.duration, now);
|
|
4014
|
+
const eased = progress >= 1 ? 1 : smoothstep(progress);
|
|
4015
|
+
const anchor = getAnchorAtDistance(animation.path, animation.path.totalDistance * eased);
|
|
4016
|
+
this.#options.applyAnchor(anchor);
|
|
4017
|
+
animation.needsMoreFrames = progress < 1;
|
|
4018
|
+
return animation.needsMoreFrames;
|
|
3906
4019
|
}
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
for (const item of [...this.#activeReplacementItems]) {
|
|
3914
|
-
if (this.#visibleItems.has(item)) continue;
|
|
3915
|
-
const animation = this.#replacementAnimations.get(item);
|
|
3916
|
-
this.#replacementAnimations.delete(item);
|
|
3917
|
-
this.#activeReplacementItems.delete(item);
|
|
3918
|
-
if (animation?.kind === "delete") adapter.onDeleteComplete(item);
|
|
3919
|
-
changed = true;
|
|
4020
|
+
finishFrame(requestRedraw) {
|
|
4021
|
+
const animation = this.#jumpAnimation;
|
|
4022
|
+
if (animation == null) return requestRedraw;
|
|
4023
|
+
if (animation.needsMoreFrames) {
|
|
4024
|
+
this.#controlledState = this.#options.readListState();
|
|
4025
|
+
return true;
|
|
3920
4026
|
}
|
|
3921
|
-
|
|
4027
|
+
const onComplete = animation.onComplete;
|
|
4028
|
+
this.#cancelJumpAnimation();
|
|
4029
|
+
onComplete?.();
|
|
4030
|
+
return requestRedraw || this.#jumpAnimation != null;
|
|
3922
4031
|
}
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4032
|
+
commit(state) {
|
|
4033
|
+
this.#lastCommittedState = {
|
|
4034
|
+
position: state.position,
|
|
4035
|
+
offset: state.offset
|
|
4036
|
+
};
|
|
3928
4037
|
}
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
readAnimation(item, now, adapter) {
|
|
3934
|
-
const animation = this.#replacementAnimations.get(item);
|
|
3935
|
-
if (animation == null) return;
|
|
3936
|
-
if (getProgress(animation.startTime, animation.duration, now) >= 1) {
|
|
3937
|
-
this.#replacementAnimations.delete(item);
|
|
3938
|
-
this.#activeReplacementItems.delete(item);
|
|
3939
|
-
if (animation.kind === "delete") adapter?.onDeleteComplete(item);
|
|
4038
|
+
jumpTo(index, options = {}) {
|
|
4039
|
+
this.#clearPendingBoundaryJumps();
|
|
4040
|
+
if (this.#options.getItemCount() === 0) {
|
|
4041
|
+
this.#cancelJumpAnimation();
|
|
3940
4042
|
return;
|
|
3941
4043
|
}
|
|
3942
|
-
|
|
3943
|
-
}
|
|
3944
|
-
/** Returns the effective rendered height for an item, accounting for animations. */
|
|
3945
|
-
getItemHeight(item, now, adapter) {
|
|
3946
|
-
const replacement = this.readAnimation(item, now);
|
|
3947
|
-
if (replacement != null) return this.#sampleReplacementHeight(replacement, now);
|
|
3948
|
-
const node = adapter.renderItem(item);
|
|
3949
|
-
return adapter.measureNode(node).height;
|
|
4044
|
+
this.#startJumpToIndex(index, options, { kind: "manual" });
|
|
3950
4045
|
}
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
return {
|
|
3957
|
-
value: {
|
|
3958
|
-
draw: (y) => adapter.drawNode(node, 0, y),
|
|
3959
|
-
hittest: (test, y) => node.hittest(adapter.getRootContext(), {
|
|
3960
|
-
...test,
|
|
3961
|
-
y: test.y - y
|
|
3962
|
-
})
|
|
3963
|
-
},
|
|
3964
|
-
height: adapter.measureNode(node).height
|
|
3965
|
-
};
|
|
4046
|
+
jumpToBoundary(boundary, options = {}) {
|
|
4047
|
+
this.#clearPendingBoundaryJumps();
|
|
4048
|
+
if (this.#options.getItemCount() === 0) {
|
|
4049
|
+
this.#cancelJumpAnimation();
|
|
4050
|
+
return;
|
|
3966
4051
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
4052
|
+
this.#armBoundaryJump(boundary);
|
|
4053
|
+
this.#startJumpToIndex(boundary === "bottom" ? this.#options.getItemCount() - 1 : 0, {
|
|
4054
|
+
...options,
|
|
4055
|
+
block: boundary === "bottom" ? "end" : "start"
|
|
4056
|
+
}, {
|
|
4057
|
+
kind: "boundary-jump",
|
|
4058
|
+
boundary
|
|
4059
|
+
});
|
|
4060
|
+
}
|
|
4061
|
+
syncAutoFollowCapabilities(capabilities) {
|
|
4062
|
+
this.#confirmedAutoFollowTop = capabilities.top;
|
|
4063
|
+
this.#confirmedAutoFollowBottom = capabilities.bottom;
|
|
4064
|
+
this.#clearPendingBoundaryJumps();
|
|
4065
|
+
return this.getEffectiveAutoFollowCapabilities();
|
|
4066
|
+
}
|
|
4067
|
+
getEffectiveAutoFollowCapabilities() {
|
|
3969
4068
|
return {
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
hittest: () => false
|
|
3973
|
-
},
|
|
3974
|
-
height: slotHeight
|
|
4069
|
+
top: this.#hasEffectiveAutoFollowCapability("top"),
|
|
4070
|
+
bottom: this.#hasEffectiveAutoFollowCapability("bottom")
|
|
3975
4071
|
};
|
|
3976
4072
|
}
|
|
3977
|
-
handleListStateChange(change
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
4073
|
+
handleListStateChange(change) {
|
|
4074
|
+
this.#hasPendingListChange = true;
|
|
4075
|
+
const followChange = this.#resolveAutoFollowChange(change);
|
|
4076
|
+
const canChainAutoFollow = followChange != null ? this.#shouldChainAutoFollow(followChange.boundary) : false;
|
|
4077
|
+
const canCapabilityAutoFollow = followChange != null ? this.#shouldAutoFollowFromCapability(followChange.boundary, followChange.direction, followChange.count) : false;
|
|
4078
|
+
if (followChange != null && (canChainAutoFollow || canCapabilityAutoFollow)) {
|
|
4079
|
+
if (canChainAutoFollow) this.#rebaseJumpAnchorForBoundaryInsert(followChange.direction, followChange.count, getNow());
|
|
4080
|
+
this.#startJumpToIndex(followChange.boundary === "bottom" ? this.#options.getItemCount() - 1 : 0, {
|
|
4081
|
+
block: followChange.boundary === "bottom" ? "end" : "start",
|
|
4082
|
+
duration: followChange.animation?.duration
|
|
4083
|
+
}, {
|
|
4084
|
+
kind: "auto-follow",
|
|
4085
|
+
boundary: followChange.boundary
|
|
4086
|
+
});
|
|
4087
|
+
return {
|
|
4088
|
+
...followChange.change,
|
|
4089
|
+
animation: void 0
|
|
4090
|
+
};
|
|
3995
4091
|
}
|
|
4092
|
+
return change;
|
|
3996
4093
|
}
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4094
|
+
#cancelJumpAnimation() {
|
|
4095
|
+
this.#jumpAnimation = void 0;
|
|
4096
|
+
this.#controlledState = void 0;
|
|
4097
|
+
}
|
|
4098
|
+
#startJumpToIndex(index, options, source) {
|
|
4099
|
+
const targetIndex = this.#options.clampItemIndex(index);
|
|
4100
|
+
const currentState = this.#options.normalizeListState(this.#options.readListState());
|
|
4101
|
+
const targetBlock = options.block ?? this.#options.getDefaultJumpBlock();
|
|
4102
|
+
const targetAnchor = this.#options.getTargetAnchor(targetIndex, targetBlock);
|
|
4103
|
+
if (!(options.animated ?? true)) {
|
|
4104
|
+
this.#cancelJumpAnimation();
|
|
4105
|
+
this.#options.applyAnchor(targetAnchor);
|
|
4106
|
+
options.onComplete?.();
|
|
4003
4107
|
return;
|
|
4004
4108
|
}
|
|
4005
|
-
const
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
let fromHeight;
|
|
4012
|
-
if (animation == null || animation.incoming == null) {
|
|
4013
|
-
currentNode = ctx.renderItem(prevItem);
|
|
4014
|
-
fromHeight = ctx.measureNode(currentNode).height;
|
|
4015
|
-
} else {
|
|
4016
|
-
currentNode = animation.incoming.node;
|
|
4017
|
-
currentAlpha = this.#sampleLayerAlpha(animation.incoming, now);
|
|
4018
|
-
fromHeight = this.#sampleReplacementHeight(animation, now);
|
|
4109
|
+
const startAnchor = this.#options.readAnchor(currentState);
|
|
4110
|
+
if (!Number.isFinite(startAnchor)) {
|
|
4111
|
+
this.#cancelJumpAnimation();
|
|
4112
|
+
this.#options.applyAnchor(targetAnchor);
|
|
4113
|
+
options.onComplete?.();
|
|
4114
|
+
return;
|
|
4019
4115
|
}
|
|
4020
|
-
const
|
|
4021
|
-
const
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
incoming,
|
|
4027
|
-
fromHeight,
|
|
4028
|
-
toHeight: nextHeight,
|
|
4029
|
-
startTime: now,
|
|
4030
|
-
duration: normalizedDuration
|
|
4031
|
-
});
|
|
4032
|
-
this.#activeReplacementItems.delete(prevItem);
|
|
4033
|
-
this.#activeReplacementItems.add(nextItem);
|
|
4034
|
-
}
|
|
4035
|
-
handleDelete(item, duration, ctx) {
|
|
4036
|
-
const normalizedDuration = Math.max(0, typeof duration === "number" && Number.isFinite(duration) ? duration : 0);
|
|
4037
|
-
const index = ctx.items.indexOf(item);
|
|
4038
|
-
if (normalizedDuration <= 0 || index < 0 || !this.#canAnimateUpdate(index, item, ctx)) {
|
|
4039
|
-
this.#replacementAnimations.delete(item);
|
|
4040
|
-
this.#activeReplacementItems.delete(item);
|
|
4041
|
-
ctx.onDeleteComplete(item);
|
|
4116
|
+
const path = buildJumpPath(this.#options.getItemCount(), this.#options.getItemHeight, startAnchor, targetAnchor);
|
|
4117
|
+
const duration = clamp$1(options.duration ?? this.#options.minJumpDuration + path.totalDistance * this.#options.jumpDurationPerPixel, 0, this.#options.maxJumpDuration);
|
|
4118
|
+
if (duration <= 0 || path.totalDistance <= Number.EPSILON) {
|
|
4119
|
+
this.#cancelJumpAnimation();
|
|
4120
|
+
this.#options.applyAnchor(targetAnchor);
|
|
4121
|
+
options.onComplete?.();
|
|
4042
4122
|
return;
|
|
4043
4123
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4124
|
+
this.#jumpAnimation = {
|
|
4125
|
+
path,
|
|
4126
|
+
startTime: getNow(),
|
|
4127
|
+
duration,
|
|
4128
|
+
needsMoreFrames: true,
|
|
4129
|
+
onComplete: options.onComplete,
|
|
4130
|
+
source
|
|
4131
|
+
};
|
|
4132
|
+
this.#controlledState = this.#options.readListState();
|
|
4133
|
+
}
|
|
4134
|
+
#resolveAutoFollowChange(change) {
|
|
4135
|
+
switch (change.type) {
|
|
4136
|
+
case "push":
|
|
4137
|
+
case "unshift": return change.animation?.autoFollow === true ? {
|
|
4138
|
+
change,
|
|
4139
|
+
boundary: change.type === "push" ? "bottom" : "top",
|
|
4140
|
+
direction: change.type,
|
|
4141
|
+
count: change.count,
|
|
4142
|
+
animation: change.animation
|
|
4143
|
+
} : void 0;
|
|
4144
|
+
default: return;
|
|
4063
4145
|
}
|
|
4064
|
-
const outgoing = currentAlpha > .001 ? this.#createLayer(currentNode, currentAlpha, 0, now, normalizedDuration) : void 0;
|
|
4065
|
-
this.#replacementAnimations.set(item, {
|
|
4066
|
-
kind: "delete",
|
|
4067
|
-
outgoing,
|
|
4068
|
-
incoming: void 0,
|
|
4069
|
-
fromHeight,
|
|
4070
|
-
toHeight: 0,
|
|
4071
|
-
startTime: now,
|
|
4072
|
-
duration: normalizedDuration
|
|
4073
|
-
});
|
|
4074
|
-
this.#activeReplacementItems.add(item);
|
|
4075
4146
|
}
|
|
4076
|
-
|
|
4147
|
+
#shouldAutoFollowFromCapability(boundary, direction, count) {
|
|
4148
|
+
return this.#hasEffectiveAutoFollowCapability(boundary) && this.#matchesLastCommittedStateAfterBoundaryInsert(direction, count);
|
|
4149
|
+
}
|
|
4150
|
+
#shouldChainAutoFollow(boundary) {
|
|
4151
|
+
return this.#readJumpBoundary() === boundary;
|
|
4152
|
+
}
|
|
4153
|
+
#rebaseJumpAnchorForBoundaryInsert(direction, count, now) {
|
|
4154
|
+
const animation = this.#jumpAnimation;
|
|
4155
|
+
if (animation == null) return;
|
|
4156
|
+
const progress = getProgress(animation.startTime, animation.duration, now);
|
|
4157
|
+
const eased = progress >= 1 ? 1 : smoothstep(progress);
|
|
4158
|
+
const anchorAtNow = getAnchorAtDistance(animation.path, animation.path.totalDistance * eased);
|
|
4159
|
+
this.#cancelJumpAnimation();
|
|
4160
|
+
this.#options.applyAnchor(direction === "unshift" ? anchorAtNow + count : anchorAtNow);
|
|
4161
|
+
}
|
|
4162
|
+
#matchesLastCommittedStateAfterBoundaryInsert(direction, count) {
|
|
4163
|
+
const state = this.#lastCommittedState;
|
|
4164
|
+
if (state == null) return false;
|
|
4165
|
+
return sameState({
|
|
4166
|
+
position: direction === "unshift" && state.position != null ? state.position + count : state.position,
|
|
4167
|
+
offset: state.offset
|
|
4168
|
+
}, this.#options.readListState().position, this.#options.readListState().offset);
|
|
4169
|
+
}
|
|
4170
|
+
#hasEffectiveAutoFollowCapability(boundary) {
|
|
4171
|
+
const animationBoundary = this.#readJumpBoundary();
|
|
4172
|
+
return boundary === "top" ? this.#confirmedAutoFollowTop || this.#pendingBoundaryJumpTop || animationBoundary === "top" : this.#confirmedAutoFollowBottom || this.#pendingBoundaryJumpBottom || animationBoundary === "bottom";
|
|
4173
|
+
}
|
|
4174
|
+
#readJumpBoundary() {
|
|
4175
|
+
const source = this.#jumpAnimation?.source;
|
|
4176
|
+
if (source == null || source.kind === "manual") return;
|
|
4177
|
+
return source.boundary;
|
|
4178
|
+
}
|
|
4179
|
+
#armBoundaryJump(boundary) {
|
|
4180
|
+
this.#pendingBoundaryJumpTop = boundary === "top";
|
|
4181
|
+
this.#pendingBoundaryJumpBottom = boundary === "bottom";
|
|
4182
|
+
}
|
|
4183
|
+
#clearPendingBoundaryJumps() {
|
|
4184
|
+
this.#pendingBoundaryJumpTop = false;
|
|
4185
|
+
this.#pendingBoundaryJumpBottom = false;
|
|
4186
|
+
}
|
|
4187
|
+
};
|
|
4188
|
+
//#endregion
|
|
4189
|
+
//#region src/renderer/virtualized/transition-snapshot.ts
|
|
4190
|
+
var VisibilitySnapshot = class {
|
|
4191
|
+
#drawnItems = /* @__PURE__ */ new Set();
|
|
4192
|
+
#visibleItems = /* @__PURE__ */ new Set();
|
|
4193
|
+
#previousVisibleItems = /* @__PURE__ */ new Set();
|
|
4194
|
+
#hasSnapshot = false;
|
|
4195
|
+
#snapshotState;
|
|
4196
|
+
#previousSnapshotState;
|
|
4197
|
+
#emptyState;
|
|
4198
|
+
#coversShortList = false;
|
|
4199
|
+
#topGap = 0;
|
|
4200
|
+
#bottomGap = 0;
|
|
4201
|
+
#atStartBoundary = false;
|
|
4202
|
+
#atEndBoundary = false;
|
|
4203
|
+
#currentExtraShift = 0;
|
|
4204
|
+
#minDrawnIndex = Number.POSITIVE_INFINITY;
|
|
4205
|
+
#maxDrawnIndex = Number.NEGATIVE_INFINITY;
|
|
4206
|
+
#topBoundaryItem;
|
|
4207
|
+
#bottomBoundaryItem;
|
|
4208
|
+
get coversShortList() {
|
|
4209
|
+
return this.#hasSnapshot && this.#snapshotState != null && this.#coversShortList;
|
|
4210
|
+
}
|
|
4211
|
+
get topGap() {
|
|
4212
|
+
return this.#topGap;
|
|
4213
|
+
}
|
|
4214
|
+
get bottomGap() {
|
|
4215
|
+
return this.#bottomGap;
|
|
4216
|
+
}
|
|
4217
|
+
get previousState() {
|
|
4218
|
+
return this.#previousSnapshotState;
|
|
4219
|
+
}
|
|
4220
|
+
get currentExtraShift() {
|
|
4221
|
+
return this.#currentExtraShift;
|
|
4222
|
+
}
|
|
4223
|
+
readDrawnIndexRange() {
|
|
4224
|
+
if (!Number.isFinite(this.#minDrawnIndex) || !Number.isFinite(this.#maxDrawnIndex)) return;
|
|
4225
|
+
return {
|
|
4226
|
+
minIndex: this.#minDrawnIndex,
|
|
4227
|
+
maxIndex: this.#maxDrawnIndex
|
|
4228
|
+
};
|
|
4229
|
+
}
|
|
4230
|
+
readBoundaryItem(boundary) {
|
|
4231
|
+
return boundary === "top" ? this.#topBoundaryItem : this.#bottomBoundaryItem;
|
|
4232
|
+
}
|
|
4233
|
+
capture(window, _resolutionPath, items, viewportHeight, snapshotState, extraShift, readVisibleRange) {
|
|
4234
|
+
this.#previousVisibleItems = this.#visibleItems;
|
|
4235
|
+
this.#previousSnapshotState = this.#snapshotState;
|
|
4236
|
+
const nextDrawnItems = /* @__PURE__ */ new Set();
|
|
4237
|
+
const nextVisibleItems = /* @__PURE__ */ new Set();
|
|
4238
|
+
let minVisibleIndex = Number.POSITIVE_INFINITY;
|
|
4239
|
+
let maxVisibleIndex = Number.NEGATIVE_INFINITY;
|
|
4240
|
+
let topMostY = Number.POSITIVE_INFINITY;
|
|
4241
|
+
let bottomMostY = Number.NEGATIVE_INFINITY;
|
|
4242
|
+
let nextMinDrawnIndex = Number.POSITIVE_INFINITY;
|
|
4243
|
+
let nextMaxDrawnIndex = Number.NEGATIVE_INFINITY;
|
|
4244
|
+
let nextTopBoundaryItem;
|
|
4245
|
+
let nextBottomBoundaryItem;
|
|
4246
|
+
let nextTopBoundaryY = Number.POSITIVE_INFINITY;
|
|
4247
|
+
let nextBottomBoundaryY = Number.NEGATIVE_INFINITY;
|
|
4248
|
+
const effectiveShift = window.shift + extraShift;
|
|
4249
|
+
for (const { idx, offset, height } of window.drawList) {
|
|
4250
|
+
minVisibleIndex = Math.min(minVisibleIndex, idx);
|
|
4251
|
+
maxVisibleIndex = Math.max(maxVisibleIndex, idx);
|
|
4252
|
+
nextMinDrawnIndex = Math.min(nextMinDrawnIndex, idx);
|
|
4253
|
+
nextMaxDrawnIndex = Math.max(nextMaxDrawnIndex, idx);
|
|
4254
|
+
const y = offset + effectiveShift;
|
|
4255
|
+
topMostY = Math.min(topMostY, y);
|
|
4256
|
+
bottomMostY = Math.max(bottomMostY, y + height);
|
|
4257
|
+
const item = items[idx];
|
|
4258
|
+
if (item != null) {
|
|
4259
|
+
nextDrawnItems.add(item);
|
|
4260
|
+
if (y < nextTopBoundaryY) {
|
|
4261
|
+
nextTopBoundaryY = y;
|
|
4262
|
+
nextTopBoundaryItem = item;
|
|
4263
|
+
}
|
|
4264
|
+
if (y + height > nextBottomBoundaryY) {
|
|
4265
|
+
nextBottomBoundaryY = y + height;
|
|
4266
|
+
nextBottomBoundaryItem = item;
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
if (item == null || readVisibleRange(y, height) == null) continue;
|
|
4270
|
+
nextVisibleItems.add(item);
|
|
4271
|
+
}
|
|
4272
|
+
this.#drawnItems = nextDrawnItems;
|
|
4273
|
+
this.#visibleItems = nextVisibleItems;
|
|
4274
|
+
this.#hasSnapshot = true;
|
|
4275
|
+
this.#snapshotState = snapshotState;
|
|
4276
|
+
this.#currentExtraShift = extraShift;
|
|
4277
|
+
this.#minDrawnIndex = nextMinDrawnIndex;
|
|
4278
|
+
this.#maxDrawnIndex = nextMaxDrawnIndex;
|
|
4279
|
+
this.#topBoundaryItem = nextTopBoundaryItem;
|
|
4280
|
+
this.#bottomBoundaryItem = nextBottomBoundaryItem;
|
|
4281
|
+
this.#emptyState = items.length === 0 && window.drawList.length === 0 ? snapshotState : void 0;
|
|
4282
|
+
const contentHeight = bottomMostY - topMostY;
|
|
4283
|
+
this.#coversShortList = window.drawList.length > 0 && items.length > 0 && window.drawList.length === items.length && minVisibleIndex === 0 && maxVisibleIndex === items.length - 1 && topMostY >= -Number.EPSILON && bottomMostY <= viewportHeight + Number.EPSILON && contentHeight < viewportHeight - Number.EPSILON;
|
|
4284
|
+
this.#topGap = this.#coversShortList ? Math.max(0, topMostY) : 0;
|
|
4285
|
+
this.#bottomGap = this.#coversShortList ? Math.max(0, viewportHeight - bottomMostY) : 0;
|
|
4286
|
+
this.#atStartBoundary = window.drawList.length > 0 && items.length > 0 && minVisibleIndex === 0 && topMostY >= -Number.EPSILON;
|
|
4287
|
+
this.#atEndBoundary = window.drawList.length > 0 && items.length > 0 && maxVisibleIndex === items.length - 1 && bottomMostY <= viewportHeight + Number.EPSILON;
|
|
4288
|
+
}
|
|
4289
|
+
matchesCurrentState(position, offset) {
|
|
4290
|
+
return this.#hasSnapshot && this.#snapshotState != null && sameState(this.#snapshotState, position, offset);
|
|
4291
|
+
}
|
|
4292
|
+
matchesBoundaryInsertState(direction, count, position, offset) {
|
|
4293
|
+
if (!this.coversShortList || this.#snapshotState == null) return false;
|
|
4294
|
+
return this.#matchesStateAfterBoundaryInsert(direction, count, position, offset);
|
|
4295
|
+
}
|
|
4296
|
+
matchesFollowBoundaryInsertState(direction, count, position, offset) {
|
|
4297
|
+
if (!this.#hasSnapshot || this.#snapshotState == null) return false;
|
|
4298
|
+
if (direction === "push" ? !this.#atEndBoundary : !this.#atStartBoundary) return false;
|
|
4299
|
+
return this.#matchesStateAfterBoundaryInsert(direction, count, position, offset);
|
|
4300
|
+
}
|
|
4301
|
+
matchesEmptyBoundaryInsertState(direction, count, position, offset) {
|
|
4302
|
+
const emptyState = this.#emptyState;
|
|
4303
|
+
if (!this.#hasSnapshot || emptyState == null) return false;
|
|
4304
|
+
return sameState({
|
|
4305
|
+
position: direction === "unshift" && emptyState.position != null ? emptyState.position + count : emptyState.position,
|
|
4306
|
+
offset: emptyState.offset
|
|
4307
|
+
}, position, offset);
|
|
4308
|
+
}
|
|
4309
|
+
isVisible(item) {
|
|
4310
|
+
return this.#visibleItems.has(item);
|
|
4311
|
+
}
|
|
4312
|
+
wasVisible(item) {
|
|
4313
|
+
return this.#previousVisibleItems.has(item);
|
|
4314
|
+
}
|
|
4315
|
+
tracks(item, retention) {
|
|
4316
|
+
return retention === "drawn" ? this.#drawnItems.has(item) : this.#visibleItems.has(item);
|
|
4317
|
+
}
|
|
4077
4318
|
reset() {
|
|
4078
|
-
this.#
|
|
4079
|
-
this.#activeReplacementItems.clear();
|
|
4319
|
+
this.#drawnItems.clear();
|
|
4080
4320
|
this.#visibleItems.clear();
|
|
4081
|
-
this.#
|
|
4082
|
-
this.#
|
|
4321
|
+
this.#previousVisibleItems.clear();
|
|
4322
|
+
this.#hasSnapshot = false;
|
|
4323
|
+
this.#snapshotState = void 0;
|
|
4324
|
+
this.#previousSnapshotState = void 0;
|
|
4325
|
+
this.#emptyState = void 0;
|
|
4326
|
+
this.#coversShortList = false;
|
|
4327
|
+
this.#topGap = 0;
|
|
4328
|
+
this.#bottomGap = 0;
|
|
4329
|
+
this.#atStartBoundary = false;
|
|
4330
|
+
this.#atEndBoundary = false;
|
|
4331
|
+
this.#currentExtraShift = 0;
|
|
4332
|
+
this.#minDrawnIndex = Number.POSITIVE_INFINITY;
|
|
4333
|
+
this.#maxDrawnIndex = Number.NEGATIVE_INFINITY;
|
|
4334
|
+
this.#topBoundaryItem = void 0;
|
|
4335
|
+
this.#bottomBoundaryItem = void 0;
|
|
4336
|
+
}
|
|
4337
|
+
#matchesStateAfterBoundaryInsert(direction, count, position, offset) {
|
|
4338
|
+
const snapshotState = this.#snapshotState;
|
|
4339
|
+
if (snapshotState == null) return false;
|
|
4340
|
+
return sameState({
|
|
4341
|
+
position: direction === "unshift" && snapshotState.position != null ? snapshotState.position + count : snapshotState.position,
|
|
4342
|
+
offset: snapshotState.offset
|
|
4343
|
+
}, position, offset);
|
|
4083
4344
|
}
|
|
4084
|
-
|
|
4345
|
+
};
|
|
4346
|
+
//#endregion
|
|
4347
|
+
//#region src/renderer/virtualized/transition-store.ts
|
|
4348
|
+
var TransitionStore = class {
|
|
4349
|
+
#transitions = /* @__PURE__ */ new Map();
|
|
4350
|
+
get size() {
|
|
4351
|
+
return this.#transitions.size;
|
|
4352
|
+
}
|
|
4353
|
+
has(item) {
|
|
4354
|
+
return this.#transitions.has(item);
|
|
4355
|
+
}
|
|
4356
|
+
set(item, transition) {
|
|
4357
|
+
this.#transitions.set(item, transition);
|
|
4358
|
+
}
|
|
4359
|
+
replace(prevItem, nextItem, transition) {
|
|
4360
|
+
this.#transitions.delete(prevItem);
|
|
4361
|
+
this.#transitions.set(nextItem, transition);
|
|
4362
|
+
}
|
|
4363
|
+
delete(item) {
|
|
4364
|
+
const transition = this.#transitions.get(item);
|
|
4365
|
+
if (transition != null) this.#transitions.delete(item);
|
|
4366
|
+
return transition;
|
|
4367
|
+
}
|
|
4368
|
+
readActive(item, now) {
|
|
4369
|
+
const transition = this.#transitions.get(item);
|
|
4370
|
+
if (transition == null) return;
|
|
4371
|
+
return this.#isComplete(transition, now) ? void 0 : transition;
|
|
4372
|
+
}
|
|
4373
|
+
prepare(now) {
|
|
4374
|
+
for (const transition of this.#transitions.values()) if (!this.#isComplete(transition, now)) return true;
|
|
4375
|
+
return false;
|
|
4376
|
+
}
|
|
4377
|
+
findCompleted(now) {
|
|
4378
|
+
return [...this.#transitions.entries()].filter(([, transition]) => this.#isComplete(transition, now)).map(([item, transition]) => ({
|
|
4379
|
+
item,
|
|
4380
|
+
transition
|
|
4381
|
+
}));
|
|
4382
|
+
}
|
|
4383
|
+
findInvisible(snapshot) {
|
|
4384
|
+
return [...this.#transitions.entries()].filter(([item, transition]) => !snapshot.tracks(item, transition.retention)).map(([item, transition]) => ({
|
|
4385
|
+
item,
|
|
4386
|
+
transition
|
|
4387
|
+
}));
|
|
4388
|
+
}
|
|
4389
|
+
reset() {
|
|
4390
|
+
this.#transitions.clear();
|
|
4391
|
+
}
|
|
4392
|
+
#isComplete(transition, now) {
|
|
4393
|
+
return getProgress(transition.height.startTime, transition.height.duration, now) >= 1;
|
|
4394
|
+
}
|
|
4395
|
+
};
|
|
4396
|
+
//#endregion
|
|
4397
|
+
//#region src/renderer/virtualized/transition-planner.ts
|
|
4398
|
+
function isFinitePositive(value) {
|
|
4399
|
+
return Number.isFinite(value) && value > 0;
|
|
4400
|
+
}
|
|
4401
|
+
function normalizeDuration(duration) {
|
|
4402
|
+
return Math.max(0, typeof duration === "number" && Number.isFinite(duration) ? duration : 0);
|
|
4403
|
+
}
|
|
4404
|
+
function createScalarAnimation(from, to, startTime, duration) {
|
|
4405
|
+
return {
|
|
4406
|
+
from,
|
|
4407
|
+
to,
|
|
4408
|
+
startTime,
|
|
4409
|
+
duration
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4412
|
+
function createLayerAnimation(node, fromAlpha, toAlpha, startTime, duration, fromTranslateY, toTranslateY) {
|
|
4413
|
+
return {
|
|
4414
|
+
node,
|
|
4415
|
+
alpha: createScalarAnimation(fromAlpha, toAlpha, startTime, duration),
|
|
4416
|
+
translateY: createScalarAnimation(fromTranslateY, toTranslateY, startTime, duration)
|
|
4417
|
+
};
|
|
4418
|
+
}
|
|
4419
|
+
function findVisibleEntry(index, resolveVisibleWindow, readVisibleRange) {
|
|
4420
|
+
if (index < 0) return;
|
|
4421
|
+
const solution = resolveVisibleWindow();
|
|
4422
|
+
for (const entry of solution.window.drawList) {
|
|
4423
|
+
if (entry.idx !== index) continue;
|
|
4424
|
+
if (readVisibleRange(entry.offset + solution.window.shift, entry.height) != null) return entry;
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
function isIndexVisible(index, resolveVisibleWindow, readVisibleRange) {
|
|
4428
|
+
return findVisibleEntry(index, resolveVisibleWindow, readVisibleRange) != null;
|
|
4429
|
+
}
|
|
4430
|
+
function resolveAnimationEligibility(params) {
|
|
4431
|
+
if (params.index < 0) return false;
|
|
4432
|
+
if (params.snapshot.matchesCurrentState(params.position, params.offset)) return params.snapshot.isVisible(params.item);
|
|
4433
|
+
return isIndexVisible(params.index, params.resolveVisibleWindow, params.readVisibleRange);
|
|
4434
|
+
}
|
|
4435
|
+
function resolveBoundaryInsertStrategy(direction, underflowAlign, coversShortListSnapshot) {
|
|
4436
|
+
if (!coversShortListSnapshot) return "hard-cut";
|
|
4437
|
+
if (direction === "push" && underflowAlign === "bottom" || direction === "unshift" && underflowAlign === "top") return "viewport-slide";
|
|
4438
|
+
return "item-enter";
|
|
4439
|
+
}
|
|
4440
|
+
function sampleScalarAnimation(animation, now) {
|
|
4441
|
+
return interpolate(animation.from, animation.to, animation.startTime, animation.duration, now);
|
|
4442
|
+
}
|
|
4443
|
+
function sampleLayerAnimation(layer, now) {
|
|
4444
|
+
const alpha = sampleScalarAnimation(layer.alpha, now);
|
|
4445
|
+
if (alpha <= .001) return;
|
|
4446
|
+
return {
|
|
4447
|
+
alpha,
|
|
4448
|
+
node: layer.node,
|
|
4449
|
+
translateY: sampleScalarAnimation(layer.translateY, now)
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4452
|
+
function sampleTransition(transition, now) {
|
|
4453
|
+
return {
|
|
4454
|
+
kind: transition.kind,
|
|
4455
|
+
slotHeight: sampleScalarAnimation(transition.height, now),
|
|
4456
|
+
layers: transition.layers.map((layer) => sampleLayerAnimation(layer, now)).filter((layer) => layer != null),
|
|
4457
|
+
retention: transition.retention
|
|
4458
|
+
};
|
|
4459
|
+
}
|
|
4460
|
+
function planExistingItemTransition(params) {
|
|
4461
|
+
if (!params.canAnimate || params.duration <= 0) return;
|
|
4462
|
+
if (params.kind === "update" && !Number.isFinite(params.nextHeight)) return;
|
|
4463
|
+
const layers = [];
|
|
4464
|
+
if (params.currentVisualState.alpha > .001) layers.push(createLayerAnimation(params.currentVisualState.node, params.currentVisualState.alpha, 0, params.now, params.duration, params.currentVisualState.translateY, 0));
|
|
4465
|
+
if (params.kind === "update") {
|
|
4466
|
+
layers.push(createLayerAnimation(params.nextNode, 0, 1, params.now, params.duration, params.currentVisualState.translateY, 0));
|
|
4085
4467
|
return {
|
|
4468
|
+
kind: "update",
|
|
4469
|
+
layers,
|
|
4470
|
+
height: createScalarAnimation(params.currentVisualState.height, params.nextHeight, params.now, params.duration),
|
|
4471
|
+
retention: "visible"
|
|
4472
|
+
};
|
|
4473
|
+
}
|
|
4474
|
+
return {
|
|
4475
|
+
kind: "delete",
|
|
4476
|
+
layers,
|
|
4477
|
+
height: createScalarAnimation(params.currentVisualState.height, 0, params.now, params.duration),
|
|
4478
|
+
retention: "visible"
|
|
4479
|
+
};
|
|
4480
|
+
}
|
|
4481
|
+
function planViewportShift(params) {
|
|
4482
|
+
if (!isFinitePositive(params.travel) || params.duration <= 0) return;
|
|
4483
|
+
return createScalarAnimation(params.direction === "positive" ? params.currentTranslateY + params.travel : params.currentTranslateY - params.travel, 0, params.now, params.duration);
|
|
4484
|
+
}
|
|
4485
|
+
function planBoundaryInsert(params) {
|
|
4486
|
+
switch (params.strategy) {
|
|
4487
|
+
case "hard-cut": return;
|
|
4488
|
+
case "item-enter": return planBoundaryInsertItems(params);
|
|
4489
|
+
case "viewport-slide": return planBoundaryInsertViewportShift(params);
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
function planBoundaryInsertItems(params) {
|
|
4493
|
+
const entries = [];
|
|
4494
|
+
const signedDistance = params.direction === "push" ? 1 : -1;
|
|
4495
|
+
for (const { item, node, height } of params.measuredItems) {
|
|
4496
|
+
if (!Number.isFinite(height) || height < 0) return;
|
|
4497
|
+
const resolvedDistance = typeof params.distance === "number" && Number.isFinite(params.distance) ? Math.max(0, params.distance) : Math.min(24, height);
|
|
4498
|
+
entries.push({
|
|
4499
|
+
item,
|
|
4500
|
+
transition: {
|
|
4501
|
+
kind: "insert",
|
|
4502
|
+
layers: [createLayerAnimation(node, 0, 1, params.now, params.duration, signedDistance * resolvedDistance, 0)],
|
|
4503
|
+
height: createScalarAnimation(height, height, params.now, params.duration),
|
|
4504
|
+
retention: "drawn"
|
|
4505
|
+
}
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4508
|
+
return entries.length === 0 ? void 0 : {
|
|
4509
|
+
kind: "item-enter",
|
|
4510
|
+
entries
|
|
4511
|
+
};
|
|
4512
|
+
}
|
|
4513
|
+
function planBoundaryInsertViewportShift(params) {
|
|
4514
|
+
let insertedHeight = 0;
|
|
4515
|
+
for (const { height } of params.measuredItems) {
|
|
4516
|
+
if (!Number.isFinite(height) || height <= 0) return;
|
|
4517
|
+
insertedHeight += height;
|
|
4518
|
+
}
|
|
4519
|
+
if (!isFinitePositive(insertedHeight)) return;
|
|
4520
|
+
const gap = params.direction === "push" ? params.snapshot.topGap : params.snapshot.bottomGap;
|
|
4521
|
+
const travel = Math.min(insertedHeight, gap);
|
|
4522
|
+
const animation = planViewportShift({
|
|
4523
|
+
currentTranslateY: params.currentTranslateY,
|
|
4524
|
+
travel,
|
|
4525
|
+
direction: params.direction === "push" ? "positive" : "negative",
|
|
4526
|
+
now: params.now,
|
|
4527
|
+
duration: params.duration
|
|
4528
|
+
});
|
|
4529
|
+
return animation == null ? void 0 : {
|
|
4530
|
+
kind: "viewport-slide",
|
|
4531
|
+
animation
|
|
4532
|
+
};
|
|
4533
|
+
}
|
|
4534
|
+
function measureBoundaryInsertItems(direction, count, ctx) {
|
|
4535
|
+
const start = direction === "push" ? ctx.items.length - count : 0;
|
|
4536
|
+
const end = direction === "push" ? ctx.items.length : Math.min(count, ctx.items.length);
|
|
4537
|
+
if (start < 0 || end < start) return;
|
|
4538
|
+
const measured = [];
|
|
4539
|
+
for (let index = start; index < end; index += 1) {
|
|
4540
|
+
const item = ctx.items[index];
|
|
4541
|
+
if (item == null) continue;
|
|
4542
|
+
const node = ctx.renderItem(item);
|
|
4543
|
+
const height = ctx.measureNode(node).height;
|
|
4544
|
+
measured.push({
|
|
4545
|
+
item,
|
|
4086
4546
|
node,
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4547
|
+
height
|
|
4548
|
+
});
|
|
4549
|
+
}
|
|
4550
|
+
return measured;
|
|
4551
|
+
}
|
|
4552
|
+
function drawSampledLayers(sampled, y, adapter) {
|
|
4553
|
+
if (sampled.slotHeight <= 0) return false;
|
|
4554
|
+
let result = false;
|
|
4555
|
+
for (const layer of sampled.layers) {
|
|
4556
|
+
const alpha = clamp$1(layer.alpha, 0, 1);
|
|
4557
|
+
if (alpha <= .001) continue;
|
|
4558
|
+
adapter.graphics.save();
|
|
4559
|
+
try {
|
|
4560
|
+
if (typeof adapter.graphics.globalAlpha === "number") adapter.graphics.globalAlpha *= alpha;
|
|
4561
|
+
if (adapter.drawNode(layer.node, 0, y + layer.translateY)) result = true;
|
|
4562
|
+
} finally {
|
|
4563
|
+
adapter.graphics.restore();
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
return result;
|
|
4567
|
+
}
|
|
4568
|
+
function planUpdateTransition(prevItem, nextItem, duration, now, currentVisualState, ctx, snapshot, store) {
|
|
4569
|
+
const nextIndex = ctx.items.indexOf(nextItem);
|
|
4570
|
+
const nextNode = ctx.renderItem(nextItem);
|
|
4571
|
+
const nextHeight = ctx.measureNode(nextNode).height;
|
|
4572
|
+
return planExistingItemTransition({
|
|
4573
|
+
kind: "update",
|
|
4574
|
+
duration: normalizeDuration(duration),
|
|
4575
|
+
canAnimate: resolveAnimationEligibility({
|
|
4576
|
+
index: nextIndex,
|
|
4577
|
+
item: prevItem,
|
|
4578
|
+
position: ctx.position,
|
|
4579
|
+
offset: ctx.offset,
|
|
4580
|
+
snapshot,
|
|
4581
|
+
hasActiveTransition: store.has(prevItem),
|
|
4582
|
+
resolveVisibleWindow: ctx.resolveVisibleWindow,
|
|
4583
|
+
readVisibleRange: ctx.readVisibleRange
|
|
4584
|
+
}),
|
|
4585
|
+
now,
|
|
4586
|
+
currentVisualState,
|
|
4587
|
+
nextNode,
|
|
4588
|
+
nextHeight
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
function planDeleteTransition(item, duration, now, currentVisualState, ctx, snapshot, store) {
|
|
4592
|
+
const index = ctx.items.indexOf(item);
|
|
4593
|
+
return planExistingItemTransition({
|
|
4594
|
+
kind: "delete",
|
|
4595
|
+
duration: normalizeDuration(duration),
|
|
4596
|
+
canAnimate: resolveAnimationEligibility({
|
|
4597
|
+
index,
|
|
4598
|
+
item,
|
|
4599
|
+
position: ctx.position,
|
|
4600
|
+
offset: ctx.offset,
|
|
4601
|
+
snapshot,
|
|
4602
|
+
hasActiveTransition: store.has(item),
|
|
4603
|
+
resolveVisibleWindow: ctx.resolveVisibleWindow,
|
|
4604
|
+
readVisibleRange: ctx.readVisibleRange
|
|
4605
|
+
}),
|
|
4606
|
+
now,
|
|
4607
|
+
currentVisualState
|
|
4608
|
+
});
|
|
4609
|
+
}
|
|
4610
|
+
function planBoundaryInsertTransition(direction, count, duration, distance, now, currentTranslateY, ctx, snapshot) {
|
|
4611
|
+
const normalizedDuration = normalizeDuration(duration);
|
|
4612
|
+
if (count <= 0 || normalizedDuration <= 0) return;
|
|
4613
|
+
const strategy = snapshot.matchesBoundaryInsertState(direction, count, ctx.position, ctx.offset) ? resolveBoundaryInsertStrategy(direction, ctx.underflowAlign, true) : snapshot.matchesEmptyBoundaryInsertState(direction, count, ctx.position, ctx.offset) ? "item-enter" : "hard-cut";
|
|
4614
|
+
if (strategy === "hard-cut") return;
|
|
4615
|
+
const measuredItems = measureBoundaryInsertItems(direction, count, ctx);
|
|
4616
|
+
if (measuredItems == null) return;
|
|
4617
|
+
return planBoundaryInsert({
|
|
4618
|
+
direction,
|
|
4619
|
+
duration: normalizedDuration,
|
|
4620
|
+
distance,
|
|
4621
|
+
now,
|
|
4622
|
+
strategy,
|
|
4623
|
+
snapshot,
|
|
4624
|
+
currentTranslateY,
|
|
4625
|
+
measuredItems
|
|
4626
|
+
});
|
|
4627
|
+
}
|
|
4628
|
+
function getTransitionedItemHeight(item, now, store, adapter) {
|
|
4629
|
+
const transition = store.readActive(item, now);
|
|
4630
|
+
if (transition != null) return sampleTransition(transition, now).slotHeight;
|
|
4631
|
+
const node = adapter.renderItem(item);
|
|
4632
|
+
return adapter.measureNode(node).height;
|
|
4633
|
+
}
|
|
4634
|
+
function resolveTransitionedItem(item, now, store, adapter, lifecycle) {
|
|
4635
|
+
const transition = store.readActive(item, now);
|
|
4636
|
+
if (transition == null) {
|
|
4637
|
+
const node = adapter.renderItem(item);
|
|
4638
|
+
return {
|
|
4639
|
+
value: {
|
|
4640
|
+
draw: (y) => adapter.drawNode(node, 0, y),
|
|
4641
|
+
hittest: (test, y) => node.hittest(adapter.getRootContext(), {
|
|
4642
|
+
...test,
|
|
4643
|
+
y: test.y - y
|
|
4644
|
+
})
|
|
4645
|
+
},
|
|
4646
|
+
height: adapter.measureNode(node).height
|
|
4647
|
+
};
|
|
4648
|
+
}
|
|
4649
|
+
const sampled = sampleTransition(transition, now);
|
|
4650
|
+
return {
|
|
4651
|
+
value: {
|
|
4652
|
+
draw: (y) => drawSampledLayers(sampled, y, adapter),
|
|
4653
|
+
hittest: () => false
|
|
4654
|
+
},
|
|
4655
|
+
height: sampled.slotHeight
|
|
4656
|
+
};
|
|
4657
|
+
}
|
|
4658
|
+
function readCurrentVisualState(item, now, store, adapter) {
|
|
4659
|
+
const transition = store.readActive(item, now);
|
|
4660
|
+
if (transition != null && transition.layers.length > 0) {
|
|
4661
|
+
const primaryLayer = transition.layers[transition.layers.length - 1];
|
|
4662
|
+
return {
|
|
4663
|
+
node: primaryLayer.node,
|
|
4664
|
+
alpha: sampleScalarAnimation(primaryLayer.alpha, now),
|
|
4665
|
+
height: sampleScalarAnimation(transition.height, now),
|
|
4666
|
+
translateY: sampleScalarAnimation(primaryLayer.translateY, now)
|
|
4091
4667
|
};
|
|
4092
4668
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4669
|
+
const node = adapter.renderItem(item);
|
|
4670
|
+
return {
|
|
4671
|
+
node,
|
|
4672
|
+
alpha: 1,
|
|
4673
|
+
height: adapter.measureNode(node).height,
|
|
4674
|
+
translateY: 0
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
function handleTransitionStateChange(store, snapshot, currentViewportTranslateY, change, ctx, lifecycle) {
|
|
4678
|
+
switch (change.type) {
|
|
4679
|
+
case "update": {
|
|
4680
|
+
const now = getNow();
|
|
4681
|
+
const currentVisualState = readCurrentVisualState(change.prevItem, now, store, ctx);
|
|
4682
|
+
const transition = planUpdateTransition(change.prevItem, change.nextItem, change.animation?.duration, now, currentVisualState, ctx, snapshot, store);
|
|
4683
|
+
if (transition == null) {
|
|
4684
|
+
store.delete(change.prevItem);
|
|
4685
|
+
return {};
|
|
4686
|
+
}
|
|
4687
|
+
store.replace(change.prevItem, change.nextItem, transition);
|
|
4688
|
+
return {};
|
|
4689
|
+
}
|
|
4690
|
+
case "delete": {
|
|
4691
|
+
const now = getNow();
|
|
4692
|
+
const currentVisualState = readCurrentVisualState(change.item, now, store, ctx);
|
|
4693
|
+
const transition = planDeleteTransition(change.item, change.animation?.duration, now, currentVisualState, ctx, snapshot, store);
|
|
4694
|
+
if (transition == null) {
|
|
4695
|
+
store.delete(change.item);
|
|
4696
|
+
lifecycle.onDeleteComplete(change.item);
|
|
4697
|
+
return {};
|
|
4698
|
+
}
|
|
4699
|
+
store.set(change.item, transition);
|
|
4700
|
+
return {};
|
|
4701
|
+
}
|
|
4702
|
+
case "delete-finalize":
|
|
4703
|
+
store.delete(change.item);
|
|
4704
|
+
return {};
|
|
4705
|
+
case "unshift":
|
|
4706
|
+
case "push": {
|
|
4707
|
+
const now = getNow();
|
|
4708
|
+
const plan = planBoundaryInsertTransition(change.type, change.count, change.animation?.duration, change.animation?.distance, now, currentViewportTranslateY, ctx, snapshot);
|
|
4709
|
+
if (plan == null) return {};
|
|
4710
|
+
if (plan.kind === "viewport-slide") return { viewportAnimation: plan.animation };
|
|
4711
|
+
for (const entry of plan.entries) store.set(entry.item, entry.transition);
|
|
4712
|
+
return {};
|
|
4713
|
+
}
|
|
4714
|
+
case "reset":
|
|
4715
|
+
case "set":
|
|
4716
|
+
store.reset();
|
|
4717
|
+
snapshot.reset();
|
|
4718
|
+
return {};
|
|
4095
4719
|
}
|
|
4096
|
-
|
|
4097
|
-
|
|
4720
|
+
}
|
|
4721
|
+
//#endregion
|
|
4722
|
+
//#region src/renderer/virtualized/base-transition.ts
|
|
4723
|
+
function remapAnchorAfterDeletes(anchor, deletedIndices) {
|
|
4724
|
+
if (!Number.isFinite(anchor) || deletedIndices.length === 0) return anchor;
|
|
4725
|
+
const sortedIndices = [...deletedIndices].filter((index) => Number.isFinite(index) && index >= 0).sort((a, b) => a - b);
|
|
4726
|
+
let removedBeforeAnchor = 0;
|
|
4727
|
+
for (const index of sortedIndices) {
|
|
4728
|
+
if (anchor > index + 1) {
|
|
4729
|
+
removedBeforeAnchor += 1;
|
|
4730
|
+
continue;
|
|
4731
|
+
}
|
|
4732
|
+
if (anchor >= index) return index - removedBeforeAnchor;
|
|
4098
4733
|
}
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4734
|
+
return anchor - removedBeforeAnchor;
|
|
4735
|
+
}
|
|
4736
|
+
var TransitionController = class {
|
|
4737
|
+
#store = new TransitionStore();
|
|
4738
|
+
#snapshot = new VisibilitySnapshot();
|
|
4739
|
+
#viewportTranslateAnimation;
|
|
4740
|
+
captureVisibilitySnapshot(window, resolutionPath, items, viewportHeight, snapshotState, extraShift, readVisibleRange) {
|
|
4741
|
+
this.#snapshot.capture(window, resolutionPath, items, viewportHeight, snapshotState, extraShift, readVisibleRange);
|
|
4105
4742
|
}
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4743
|
+
pruneInvisible(ctx, lifecycle) {
|
|
4744
|
+
return this.pruneInvisibleAt(getNow(), ctx, lifecycle);
|
|
4745
|
+
}
|
|
4746
|
+
prepare(now, lifecycle) {
|
|
4747
|
+
this.settle(now, lifecycle);
|
|
4748
|
+
this.#cleanupViewportTranslateAnimation(now);
|
|
4749
|
+
const keepViewportAnimating = this.#viewportTranslateAnimation != null;
|
|
4750
|
+
return this.#store.prepare(now) || keepViewportAnimating;
|
|
4751
|
+
}
|
|
4752
|
+
getViewportTranslateY(now) {
|
|
4753
|
+
this.#cleanupViewportTranslateAnimation(now);
|
|
4754
|
+
return this.#viewportTranslateAnimation == null ? 0 : sampleScalarAnimation(this.#viewportTranslateAnimation, now);
|
|
4755
|
+
}
|
|
4756
|
+
canAutoFollowBoundaryInsert(direction, count, position, offset) {
|
|
4757
|
+
return this.#snapshot.matchesFollowBoundaryInsertState(direction, count, position, offset);
|
|
4758
|
+
}
|
|
4759
|
+
getItemHeight(item, now, adapter) {
|
|
4760
|
+
return getTransitionedItemHeight(item, now, this.#store, adapter);
|
|
4761
|
+
}
|
|
4762
|
+
resolveItem(item, now, adapter, lifecycle) {
|
|
4763
|
+
return resolveTransitionedItem(item, now, this.#store, adapter, lifecycle);
|
|
4764
|
+
}
|
|
4765
|
+
handleListStateChange(change, ctx, lifecycle) {
|
|
4766
|
+
const now = getNow();
|
|
4767
|
+
this.settle(now, lifecycle);
|
|
4768
|
+
const result = handleTransitionStateChange(this.#store, this.#snapshot, this.getViewportTranslateY(now), change, ctx, lifecycle);
|
|
4769
|
+
if (change.type === "reset" || change.type === "set") {
|
|
4770
|
+
this.#viewportTranslateAnimation = void 0;
|
|
4771
|
+
return;
|
|
4772
|
+
}
|
|
4773
|
+
if (result.viewportAnimation != null) this.#viewportTranslateAnimation = result.viewportAnimation;
|
|
4774
|
+
}
|
|
4775
|
+
settle(now, lifecycle) {
|
|
4776
|
+
const changed = this.#settleTransitions(this.#store.findCompleted(now), now, lifecycle);
|
|
4777
|
+
this.#cleanupViewportTranslateAnimation(now);
|
|
4778
|
+
return changed;
|
|
4779
|
+
}
|
|
4780
|
+
pruneInvisibleAt(now, ctx, lifecycle) {
|
|
4781
|
+
const removals = this.#store.findInvisible(this.#snapshot);
|
|
4782
|
+
return this.#settleTransitions(removals, now, lifecycle, this.#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle));
|
|
4783
|
+
}
|
|
4784
|
+
reset() {
|
|
4785
|
+
this.#store.reset();
|
|
4786
|
+
this.#snapshot.reset();
|
|
4787
|
+
this.#viewportTranslateAnimation = void 0;
|
|
4788
|
+
}
|
|
4789
|
+
#cleanupViewportTranslateAnimation(now) {
|
|
4790
|
+
const animation = this.#viewportTranslateAnimation;
|
|
4791
|
+
if (animation == null) return;
|
|
4792
|
+
if (getProgress(animation.startTime, animation.duration, now) >= 1) this.#viewportTranslateAnimation = void 0;
|
|
4793
|
+
}
|
|
4794
|
+
#settleTransitions(removals, now, lifecycle, boundarySnap) {
|
|
4795
|
+
if (removals.length === 0) return false;
|
|
4796
|
+
const anchor = lifecycle.captureVisualAnchor(now);
|
|
4797
|
+
const completedDeleteIndices = [];
|
|
4798
|
+
for (const { item, transition } of removals) {
|
|
4799
|
+
if (transition.kind === "delete") {
|
|
4800
|
+
const index = lifecycle.readItemIndex(item);
|
|
4801
|
+
if (index >= 0) completedDeleteIndices.push(index);
|
|
4123
4802
|
}
|
|
4803
|
+
this.#store.delete(item);
|
|
4804
|
+
if (transition.kind === "delete") lifecycle.onDeleteComplete(item);
|
|
4805
|
+
}
|
|
4806
|
+
if (anchor != null && Number.isFinite(anchor)) lifecycle.restoreVisualAnchor(remapAnchorAfterDeletes(anchor, completedDeleteIndices));
|
|
4807
|
+
if (boundarySnap != null) lifecycle.snapItemToViewportBoundary(boundarySnap.item, boundarySnap.boundary);
|
|
4808
|
+
return true;
|
|
4809
|
+
}
|
|
4810
|
+
#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle) {
|
|
4811
|
+
const previousState = this.#snapshot.previousState;
|
|
4812
|
+
const drawnRange = this.#snapshot.readDrawnIndexRange();
|
|
4813
|
+
if (previousState == null || drawnRange == null) return;
|
|
4814
|
+
const naturalIndices = [];
|
|
4815
|
+
for (const { item, transition } of removals) {
|
|
4816
|
+
if (transition.kind !== "update" && transition.kind !== "delete") continue;
|
|
4817
|
+
const index = lifecycle.readItemIndex(item);
|
|
4818
|
+
if (index < 0 || !this.#snapshot.wasVisible(item)) return;
|
|
4819
|
+
if (this.#isTransitionVisibleInState(index, previousState, now, this.#snapshot.currentExtraShift, ctx)) return;
|
|
4820
|
+
naturalIndices.push(index);
|
|
4821
|
+
}
|
|
4822
|
+
if (naturalIndices.length === 0) return;
|
|
4823
|
+
if (naturalIndices.every((index) => index < drawnRange.minIndex)) {
|
|
4824
|
+
const item = this.#snapshot.readBoundaryItem("top");
|
|
4825
|
+
return item == null ? void 0 : {
|
|
4826
|
+
item,
|
|
4827
|
+
boundary: "top"
|
|
4828
|
+
};
|
|
4829
|
+
}
|
|
4830
|
+
if (naturalIndices.every((index) => index > drawnRange.maxIndex)) {
|
|
4831
|
+
const item = this.#snapshot.readBoundaryItem("bottom");
|
|
4832
|
+
return item == null ? void 0 : {
|
|
4833
|
+
item,
|
|
4834
|
+
boundary: "bottom"
|
|
4835
|
+
};
|
|
4124
4836
|
}
|
|
4125
|
-
return result;
|
|
4126
4837
|
}
|
|
4127
|
-
#
|
|
4128
|
-
|
|
4129
|
-
const solution = resolveVisibleWindow();
|
|
4838
|
+
#isTransitionVisibleInState(index, state, now, extraShift, ctx) {
|
|
4839
|
+
const solution = ctx.resolveVisibleWindowForState(state, now);
|
|
4130
4840
|
for (const entry of solution.window.drawList) {
|
|
4131
4841
|
if (entry.idx !== index) continue;
|
|
4132
|
-
|
|
4842
|
+
return ctx.readVisibleRange(entry.offset + solution.window.shift + extraShift, entry.height) != null;
|
|
4133
4843
|
}
|
|
4134
4844
|
return false;
|
|
4135
4845
|
}
|
|
4136
|
-
#canAnimateUpdate(nextIndex, prevItem, ctx) {
|
|
4137
|
-
if (nextIndex < 0) return false;
|
|
4138
|
-
if (this.#hasVisibleItemSnapshot && this.#visibleSnapshotState != null && sameState(this.#visibleSnapshotState, ctx.position, ctx.offset)) return this.#visibleItems.has(prevItem) || this.#activeReplacementItems.has(prevItem);
|
|
4139
|
-
return this.#isIndexVisible(nextIndex, ctx.resolveVisibleWindow, ctx.readVisibleRange);
|
|
4140
|
-
}
|
|
4141
4846
|
};
|
|
4142
4847
|
//#endregion
|
|
4143
4848
|
//#region src/renderer/virtualized/base.ts
|
|
@@ -4147,12 +4852,25 @@ var ReplacementController = class {
|
|
|
4147
4852
|
var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
4148
4853
|
static MIN_JUMP_DURATION = 160;
|
|
4149
4854
|
static MAX_JUMP_DURATION = 420;
|
|
4150
|
-
static
|
|
4151
|
-
#
|
|
4152
|
-
#
|
|
4153
|
-
#replacementController = new ReplacementController();
|
|
4855
|
+
static JUMP_DURATION_PER_PIXEL = .7;
|
|
4856
|
+
#jumpController;
|
|
4857
|
+
#transitionController = new TransitionController();
|
|
4154
4858
|
constructor(graphics, options) {
|
|
4155
4859
|
super(graphics, options);
|
|
4860
|
+
this.#jumpController = new JumpController({
|
|
4861
|
+
minJumpDuration: VirtualizedRenderer.MIN_JUMP_DURATION,
|
|
4862
|
+
maxJumpDuration: VirtualizedRenderer.MAX_JUMP_DURATION,
|
|
4863
|
+
jumpDurationPerPixel: VirtualizedRenderer.JUMP_DURATION_PER_PIXEL,
|
|
4864
|
+
getItemCount: () => this.items.length,
|
|
4865
|
+
readListState: this._readListState.bind(this),
|
|
4866
|
+
normalizeListState: this._normalizeListState.bind(this),
|
|
4867
|
+
readAnchor: (state) => this._readAnchor(state, this._getItemHeight.bind(this)),
|
|
4868
|
+
applyAnchor: this._applyAnchor.bind(this),
|
|
4869
|
+
getDefaultJumpBlock: this._getDefaultJumpBlock.bind(this),
|
|
4870
|
+
getTargetAnchor: this._getTargetAnchor.bind(this),
|
|
4871
|
+
clampItemIndex: this._clampItemIndex.bind(this),
|
|
4872
|
+
getItemHeight: this._getItemHeight.bind(this)
|
|
4873
|
+
});
|
|
4156
4874
|
subscribeListState(options.list, this, (owner, change) => {
|
|
4157
4875
|
owner.#handleListStateChange(change);
|
|
4158
4876
|
});
|
|
@@ -4183,30 +4901,41 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
4183
4901
|
}
|
|
4184
4902
|
/** Renders the current visible window. */
|
|
4185
4903
|
render(feedback) {
|
|
4904
|
+
this.#jumpController.beforeFrame();
|
|
4186
4905
|
const now = getNow();
|
|
4187
4906
|
const keepAnimating = this._prepareRender(now);
|
|
4188
4907
|
const { clientWidth: viewportWidth, clientHeight: viewportHeight } = this.graphics.canvas;
|
|
4189
4908
|
this.graphics.clearRect(0, 0, viewportWidth, viewportHeight);
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
solution
|
|
4195
|
-
this.
|
|
4909
|
+
const frame = prepareFrameSession({
|
|
4910
|
+
now,
|
|
4911
|
+
resolveVisibleWindow: (frameNow) => this._resolveVisibleWindow(frameNow),
|
|
4912
|
+
getViewportTranslateY: (frameNow) => this.#transitionController.getViewportTranslateY(frameNow),
|
|
4913
|
+
captureVisibleItemSnapshot: (solution, extraShift) => this._captureVisibleItemSnapshot(solution, extraShift),
|
|
4914
|
+
pruneTransitionAnimations: (window, frameNow) => this._pruneTransitionAnimations(window, frameNow)
|
|
4915
|
+
});
|
|
4916
|
+
const autoFollowCapabilities = this.#jumpController.syncAutoFollowCapabilities(this._readAutoFollowCapabilities(frame.solution.window, frame.viewportTranslateY));
|
|
4917
|
+
const requestRedraw = this._renderVisibleWindow(frame.solution.window, feedback, frame.viewportTranslateY);
|
|
4918
|
+
if (feedback != null) {
|
|
4919
|
+
feedback.canAutoFollowTop = autoFollowCapabilities.top;
|
|
4920
|
+
feedback.canAutoFollowBottom = autoFollowCapabilities.bottom;
|
|
4196
4921
|
}
|
|
4197
|
-
|
|
4198
|
-
this.
|
|
4199
|
-
return this._finishRender(keepAnimating || requestRedraw || requestSettleRedraw);
|
|
4922
|
+
this._commitListState(frame.solution.normalizedState);
|
|
4923
|
+
return this._finishRender(keepAnimating || requestRedraw || frame.requestSettleRedraw);
|
|
4200
4924
|
}
|
|
4201
4925
|
/** Hit-tests the current visible window. */
|
|
4202
4926
|
hittest(test) {
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4927
|
+
this.#jumpController.beforeFrame();
|
|
4928
|
+
const now = getNow();
|
|
4929
|
+
this.#transitionController.settle(now, this.#getTransitionLifecycleAdapter());
|
|
4930
|
+
const frame = prepareFrameSession({
|
|
4931
|
+
now,
|
|
4932
|
+
resolveVisibleWindow: (frameNow) => this._resolveVisibleWindow(frameNow),
|
|
4933
|
+
getViewportTranslateY: (frameNow) => this.#transitionController.getViewportTranslateY(frameNow),
|
|
4934
|
+
captureVisibleItemSnapshot: (solution, extraShift) => this._captureVisibleItemSnapshot(solution, extraShift),
|
|
4935
|
+
pruneTransitionAnimations: (window, frameNow) => this._pruneTransitionAnimations(window, frameNow)
|
|
4936
|
+
});
|
|
4937
|
+
this.#jumpController.syncAutoFollowCapabilities(this._readAutoFollowCapabilities(frame.solution.window, frame.viewportTranslateY));
|
|
4938
|
+
return this._hittestVisibleWindow(frame.solution.window, test, frame.viewportTranslateY);
|
|
4210
4939
|
}
|
|
4211
4940
|
_readListState() {
|
|
4212
4941
|
return {
|
|
@@ -4214,51 +4943,31 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
4214
4943
|
offset: this.offset
|
|
4215
4944
|
};
|
|
4216
4945
|
}
|
|
4946
|
+
_resolveVisibleWindow(now) {
|
|
4947
|
+
return this._resolveVisibleWindowForState(this._readListState(), now);
|
|
4948
|
+
}
|
|
4217
4949
|
_commitListState(state) {
|
|
4218
4950
|
this.position = state.position;
|
|
4219
4951
|
this.offset = state.offset;
|
|
4952
|
+
this.#jumpController.commit(state);
|
|
4220
4953
|
}
|
|
4221
4954
|
/**
|
|
4222
4955
|
* Scrolls the viewport to the requested item index.
|
|
4223
4956
|
*/
|
|
4224
4957
|
jumpTo(index, options = {}) {
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
}
|
|
4239
|
-
const startAnchor = this._readAnchor(currentState);
|
|
4240
|
-
if (!Number.isFinite(startAnchor)) {
|
|
4241
|
-
this.#cancelJumpAnimation();
|
|
4242
|
-
this._applyAnchor(targetAnchor);
|
|
4243
|
-
options.onComplete?.();
|
|
4244
|
-
return;
|
|
4245
|
-
}
|
|
4246
|
-
const duration = clamp$3(options.duration ?? VirtualizedRenderer.MIN_JUMP_DURATION + Math.abs(targetAnchor - startAnchor) * VirtualizedRenderer.JUMP_DURATION_PER_ITEM, 0, VirtualizedRenderer.MAX_JUMP_DURATION);
|
|
4247
|
-
if (duration <= 0 || Math.abs(targetAnchor - startAnchor) <= Number.EPSILON) {
|
|
4248
|
-
this.#cancelJumpAnimation();
|
|
4249
|
-
this._applyAnchor(targetAnchor);
|
|
4250
|
-
options.onComplete?.();
|
|
4251
|
-
return;
|
|
4252
|
-
}
|
|
4253
|
-
this.#jumpAnimation = {
|
|
4254
|
-
startAnchor,
|
|
4255
|
-
targetAnchor,
|
|
4256
|
-
startTime: getNow(),
|
|
4257
|
-
duration,
|
|
4258
|
-
needsMoreFrames: true,
|
|
4259
|
-
onComplete: options.onComplete
|
|
4260
|
-
};
|
|
4261
|
-
this.#controlledState = this._readListState();
|
|
4958
|
+
this.#jumpController.jumpTo(index, options);
|
|
4959
|
+
}
|
|
4960
|
+
/**
|
|
4961
|
+
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
4962
|
+
*/
|
|
4963
|
+
jumpToTop(options = {}) {
|
|
4964
|
+
this.#jumpController.jumpToBoundary("top", options);
|
|
4965
|
+
}
|
|
4966
|
+
/**
|
|
4967
|
+
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
4968
|
+
*/
|
|
4969
|
+
jumpToBottom(options = {}) {
|
|
4970
|
+
this.#jumpController.jumpToBoundary("bottom", options);
|
|
4262
4971
|
}
|
|
4263
4972
|
_resetRenderFeedback(feedback) {
|
|
4264
4973
|
if (feedback == null) return;
|
|
@@ -4266,6 +4975,8 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
4266
4975
|
feedback.maxIdx = NaN;
|
|
4267
4976
|
feedback.min = NaN;
|
|
4268
4977
|
feedback.max = NaN;
|
|
4978
|
+
feedback.canAutoFollowTop = false;
|
|
4979
|
+
feedback.canAutoFollowBottom = false;
|
|
4269
4980
|
}
|
|
4270
4981
|
_accumulateRenderFeedback(feedback, idx, top, height) {
|
|
4271
4982
|
const visibleRange = this._readVisibleRange(top, height);
|
|
@@ -4288,178 +4999,262 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
4288
4999
|
}
|
|
4289
5000
|
return result;
|
|
4290
5001
|
}
|
|
4291
|
-
_renderVisibleWindow(window, feedback) {
|
|
5002
|
+
_renderVisibleWindow(window, feedback, extraShift = 0) {
|
|
4292
5003
|
this._resetRenderFeedback(feedback);
|
|
4293
|
-
return this._renderDrawList(window.drawList, window.shift, feedback);
|
|
5004
|
+
return this._renderDrawList(window.drawList, window.shift + extraShift, feedback);
|
|
5005
|
+
}
|
|
5006
|
+
_readAutoFollowCapabilities(window, extraShift = 0) {
|
|
5007
|
+
if (window.drawList.length === 0 || this.items.length === 0) return {
|
|
5008
|
+
top: false,
|
|
5009
|
+
bottom: false
|
|
5010
|
+
};
|
|
5011
|
+
let minIndex = Number.POSITIVE_INFINITY;
|
|
5012
|
+
let maxIndex = Number.NEGATIVE_INFINITY;
|
|
5013
|
+
let topMostY = Number.POSITIVE_INFINITY;
|
|
5014
|
+
let bottomMostY = Number.NEGATIVE_INFINITY;
|
|
5015
|
+
const effectiveShift = window.shift + extraShift;
|
|
5016
|
+
for (const { idx, offset, height } of window.drawList) {
|
|
5017
|
+
minIndex = Math.min(minIndex, idx);
|
|
5018
|
+
maxIndex = Math.max(maxIndex, idx);
|
|
5019
|
+
const y = offset + effectiveShift;
|
|
5020
|
+
topMostY = Math.min(topMostY, y);
|
|
5021
|
+
bottomMostY = Math.max(bottomMostY, y + height);
|
|
5022
|
+
}
|
|
5023
|
+
const viewportHeight = this.graphics.canvas.clientHeight;
|
|
5024
|
+
return {
|
|
5025
|
+
top: minIndex === 0 && topMostY >= -Number.EPSILON,
|
|
5026
|
+
bottom: maxIndex === this.items.length - 1 && bottomMostY <= viewportHeight + Number.EPSILON
|
|
5027
|
+
};
|
|
4294
5028
|
}
|
|
4295
5029
|
_readVisibleRange(top, height) {
|
|
4296
5030
|
if (!Number.isFinite(top) || !Number.isFinite(height) || height <= 0) return;
|
|
4297
5031
|
const viewportHeight = this.graphics.canvas.clientHeight;
|
|
4298
|
-
const visibleTop = clamp$
|
|
4299
|
-
const visibleBottom = clamp$
|
|
5032
|
+
const visibleTop = clamp$1(-top, 0, height);
|
|
5033
|
+
const visibleBottom = clamp$1(viewportHeight - top, 0, height);
|
|
4300
5034
|
if (visibleBottom <= visibleTop) return;
|
|
4301
5035
|
return {
|
|
4302
5036
|
top: visibleTop,
|
|
4303
5037
|
bottom: visibleBottom
|
|
4304
5038
|
};
|
|
4305
5039
|
}
|
|
4306
|
-
|
|
4307
|
-
return this.#
|
|
5040
|
+
_pruneTransitionAnimations(_window, now) {
|
|
5041
|
+
return this.#transitionController.pruneInvisibleAt(now, this.#getTransitionPlanningAdapter(), this.#getTransitionLifecycleAdapter());
|
|
4308
5042
|
}
|
|
4309
|
-
_hittestVisibleWindow(window, test) {
|
|
5043
|
+
_hittestVisibleWindow(window, test, extraShift = 0) {
|
|
4310
5044
|
for (const { value: item, offset, height } of window.drawList) {
|
|
4311
|
-
const y = offset + window.shift;
|
|
5045
|
+
const y = offset + window.shift + extraShift;
|
|
4312
5046
|
if (test.y < y || test.y >= y + height) continue;
|
|
4313
5047
|
return item.hittest(test, y);
|
|
4314
5048
|
}
|
|
4315
5049
|
return false;
|
|
4316
5050
|
}
|
|
4317
|
-
_captureVisibleItemSnapshot(
|
|
4318
|
-
|
|
5051
|
+
_captureVisibleItemSnapshot(solution, extraShift = 0) {
|
|
5052
|
+
const normalizedState = this._normalizeListState(this._readListState());
|
|
5053
|
+
this.#transitionController.captureVisibilitySnapshot(solution.window, solution.resolutionPath, this.items, this.graphics.canvas.clientHeight, normalizedState, extraShift, this._readVisibleRange.bind(this));
|
|
4319
5054
|
}
|
|
4320
5055
|
_prepareRender(now) {
|
|
4321
|
-
const
|
|
4322
|
-
const
|
|
4323
|
-
|
|
4324
|
-
if (this.items.length === 0) {
|
|
4325
|
-
this.#cancelJumpAnimation();
|
|
4326
|
-
return keepReplacing;
|
|
4327
|
-
}
|
|
4328
|
-
if (this.#controlledState != null && !sameState(this.#controlledState, this.position, this.offset)) {
|
|
4329
|
-
this.#cancelJumpAnimation();
|
|
4330
|
-
return keepReplacing;
|
|
4331
|
-
}
|
|
4332
|
-
const anchor = interpolate(animation.startAnchor, animation.targetAnchor, animation.startTime, animation.duration, now);
|
|
4333
|
-
const progress = getProgress(animation.startTime, animation.duration, now);
|
|
4334
|
-
this._applyAnchor(anchor);
|
|
4335
|
-
animation.needsMoreFrames = progress < 1;
|
|
4336
|
-
return keepReplacing || animation.needsMoreFrames;
|
|
5056
|
+
const keepTransitioning = this.#transitionController.prepare(now, this.#getTransitionLifecycleAdapter());
|
|
5057
|
+
const keepJumping = this.#jumpController.prepare(now);
|
|
5058
|
+
return keepTransitioning || keepJumping;
|
|
4337
5059
|
}
|
|
4338
5060
|
_finishRender(requestRedraw) {
|
|
4339
|
-
|
|
4340
|
-
if (animation == null) return requestRedraw;
|
|
4341
|
-
if (animation.needsMoreFrames) {
|
|
4342
|
-
this.#controlledState = this._readListState();
|
|
4343
|
-
return true;
|
|
4344
|
-
}
|
|
4345
|
-
const onComplete = animation.onComplete;
|
|
4346
|
-
this.#cancelJumpAnimation();
|
|
4347
|
-
onComplete?.();
|
|
4348
|
-
return requestRedraw || this.#jumpAnimation != null;
|
|
5061
|
+
return this.#jumpController.finishFrame(requestRedraw);
|
|
4349
5062
|
}
|
|
4350
5063
|
_clampItemIndex(index) {
|
|
4351
|
-
return clamp$
|
|
5064
|
+
return clamp$1(Number.isFinite(index) ? Math.trunc(index) : 0, 0, this.items.length - 1);
|
|
4352
5065
|
}
|
|
4353
5066
|
_getItemHeight(index) {
|
|
5067
|
+
return this._getItemHeightAt(index, getNow());
|
|
5068
|
+
}
|
|
5069
|
+
_getItemHeightAt(index, now) {
|
|
4354
5070
|
const item = this.items[index];
|
|
4355
|
-
return this.#
|
|
5071
|
+
return this.#transitionController.getItemHeight(item, now, {
|
|
4356
5072
|
renderItem: this.options.renderItem,
|
|
4357
5073
|
measureNode: this.measureRootNode.bind(this)
|
|
4358
5074
|
});
|
|
4359
5075
|
}
|
|
4360
|
-
|
|
4361
|
-
|
|
5076
|
+
_readAnchorAt(now) {
|
|
5077
|
+
if (this.items.length <= 0) return;
|
|
5078
|
+
const state = this._normalizeListState(this._readListState());
|
|
5079
|
+
return this._readAnchor(state, (index) => this._getItemHeightAt(index, now));
|
|
4362
5080
|
}
|
|
4363
|
-
|
|
4364
|
-
if (this.items.length
|
|
4365
|
-
|
|
4366
|
-
let remaining = Number.isFinite(offset) ? offset : 0;
|
|
4367
|
-
while (true) {
|
|
4368
|
-
if (remaining < 0) {
|
|
4369
|
-
if (currentIndex === 0) return 0;
|
|
4370
|
-
currentIndex -= 1;
|
|
4371
|
-
const height = this._getItemHeight(currentIndex);
|
|
4372
|
-
if (height > 0) remaining += height;
|
|
4373
|
-
continue;
|
|
4374
|
-
}
|
|
4375
|
-
const height = this._getItemHeight(currentIndex);
|
|
4376
|
-
if (height > 0) {
|
|
4377
|
-
if (remaining <= height) return currentIndex + remaining / height;
|
|
4378
|
-
remaining -= height;
|
|
4379
|
-
} else if (remaining === 0) return currentIndex;
|
|
4380
|
-
if (currentIndex === this.items.length - 1) return this.items.length;
|
|
4381
|
-
currentIndex += 1;
|
|
4382
|
-
}
|
|
5081
|
+
_restoreAnchor(anchor) {
|
|
5082
|
+
if (!Number.isFinite(anchor) || this.items.length <= 0) return;
|
|
5083
|
+
this._applyAnchor(anchor);
|
|
4383
5084
|
}
|
|
4384
|
-
#
|
|
4385
|
-
|
|
4386
|
-
|
|
5085
|
+
#snapItemToViewportBoundary(item, boundary) {
|
|
5086
|
+
const index = this.items.indexOf(item);
|
|
5087
|
+
if (index < 0) return;
|
|
5088
|
+
this._applyAnchor(this._getTargetAnchor(index, boundary === "top" ? "start" : "end"));
|
|
5089
|
+
}
|
|
5090
|
+
_resolveItem(item, _index, now) {
|
|
5091
|
+
return this.#transitionController.resolveItem(item, now, this.#getTransitionRenderAdapter(), this.#getTransitionLifecycleAdapter());
|
|
4387
5092
|
}
|
|
4388
5093
|
#handleDeleteComplete(item) {
|
|
4389
5094
|
this.options.list.finalizeDelete(item);
|
|
4390
5095
|
}
|
|
4391
|
-
#
|
|
5096
|
+
#getTransitionLifecycleAdapter() {
|
|
4392
5097
|
return {
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
getAnimatedLayerOffset: this._getAnimatedLayerOffset.bind(this),
|
|
4399
|
-
onDeleteComplete: this.#handleDeleteComplete.bind(this)
|
|
5098
|
+
onDeleteComplete: this.#handleDeleteComplete.bind(this),
|
|
5099
|
+
captureVisualAnchor: this._readAnchorAt.bind(this),
|
|
5100
|
+
restoreVisualAnchor: this._restoreAnchor.bind(this),
|
|
5101
|
+
readItemIndex: (item) => this.items.indexOf(item),
|
|
5102
|
+
snapItemToViewportBoundary: this.#snapItemToViewportBoundary.bind(this)
|
|
4400
5103
|
};
|
|
4401
5104
|
}
|
|
4402
|
-
#
|
|
5105
|
+
#getVirtualizedRuntime() {
|
|
4403
5106
|
return {
|
|
4404
|
-
...this.#getReplacementRendererAdapter(),
|
|
4405
5107
|
items: this.items,
|
|
4406
5108
|
position: this.position,
|
|
4407
5109
|
offset: this.offset,
|
|
4408
|
-
|
|
5110
|
+
renderItem: this.options.renderItem,
|
|
5111
|
+
measureNode: this.measureRootNode.bind(this),
|
|
4409
5112
|
readVisibleRange: this._readVisibleRange.bind(this),
|
|
4410
|
-
resolveVisibleWindow: () => this._resolveVisibleWindow(getNow())
|
|
5113
|
+
resolveVisibleWindow: () => this._resolveVisibleWindow(getNow()),
|
|
5114
|
+
resolveVisibleWindowForState: (state, now) => this._resolveVisibleWindowForState(state, now)
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
#getTransitionRenderAdapter() {
|
|
5118
|
+
const runtime = this.#getVirtualizedRuntime();
|
|
5119
|
+
return {
|
|
5120
|
+
renderItem: runtime.renderItem,
|
|
5121
|
+
measureNode: runtime.measureNode,
|
|
5122
|
+
drawNode: this.drawRootNode.bind(this),
|
|
5123
|
+
getRootContext: this.getRootContext.bind(this),
|
|
5124
|
+
graphics: this.graphics
|
|
5125
|
+
};
|
|
5126
|
+
}
|
|
5127
|
+
#getTransitionPlanningAdapter() {
|
|
5128
|
+
return {
|
|
5129
|
+
...this.#getVirtualizedRuntime(),
|
|
5130
|
+
underflowAlign: this._getLayoutOptions().underflowAlign
|
|
4411
5131
|
};
|
|
4412
5132
|
}
|
|
4413
5133
|
#handleListStateChange(change) {
|
|
4414
|
-
this.#
|
|
5134
|
+
const nextChange = this.#jumpController.handleListStateChange(change);
|
|
5135
|
+
this.#transitionController.handleListStateChange(nextChange, this.#getTransitionPlanningAdapter(), this.#getTransitionLifecycleAdapter());
|
|
4415
5136
|
}
|
|
4416
5137
|
};
|
|
4417
5138
|
//#endregion
|
|
5139
|
+
//#region src/renderer/virtualized/anchor-model.ts
|
|
5140
|
+
function clampItemIndex(index, itemCount) {
|
|
5141
|
+
if (itemCount <= 0) return 0;
|
|
5142
|
+
return clamp$1(Number.isFinite(index) ? Math.trunc(index) : 0, 0, itemCount - 1);
|
|
5143
|
+
}
|
|
5144
|
+
function readAnchorFromState(itemCount, state, anchorMode, readItemHeight) {
|
|
5145
|
+
if (itemCount <= 0) return 0;
|
|
5146
|
+
const height = readItemHeight(state.position);
|
|
5147
|
+
if (anchorMode === "top") return height > 0 ? state.position - state.offset / height : state.position;
|
|
5148
|
+
return height > 0 ? state.position + 1 - state.offset / height : state.position + 1;
|
|
5149
|
+
}
|
|
5150
|
+
function applyAnchorToState(itemCount, anchor, anchorMode, readItemHeight) {
|
|
5151
|
+
if (itemCount <= 0) return;
|
|
5152
|
+
const clampedAnchor = clamp$1(anchor, 0, itemCount);
|
|
5153
|
+
if (anchorMode === "top") {
|
|
5154
|
+
const position = clamp$1(Math.floor(clampedAnchor), 0, itemCount - 1);
|
|
5155
|
+
const height = readItemHeight(position);
|
|
5156
|
+
const offset = height > 0 ? -(clampedAnchor - position) * height : 0;
|
|
5157
|
+
return {
|
|
5158
|
+
position,
|
|
5159
|
+
offset: Object.is(offset, -0) ? 0 : offset
|
|
5160
|
+
};
|
|
5161
|
+
}
|
|
5162
|
+
const position = clamp$1(Math.ceil(clampedAnchor) - 1, 0, itemCount - 1);
|
|
5163
|
+
const height = readItemHeight(position);
|
|
5164
|
+
const offset = height > 0 ? (position + 1 - clampedAnchor) * height : 0;
|
|
5165
|
+
return {
|
|
5166
|
+
position,
|
|
5167
|
+
offset: Object.is(offset, -0) ? 0 : offset
|
|
5168
|
+
};
|
|
5169
|
+
}
|
|
5170
|
+
function getAnchorAtOffset(itemCount, index, offset, readItemHeight) {
|
|
5171
|
+
if (itemCount <= 0) return 0;
|
|
5172
|
+
let currentIndex = clampItemIndex(index, itemCount);
|
|
5173
|
+
let remaining = Number.isFinite(offset) ? offset : 0;
|
|
5174
|
+
while (true) {
|
|
5175
|
+
if (remaining < 0) {
|
|
5176
|
+
if (currentIndex === 0) return 0;
|
|
5177
|
+
currentIndex -= 1;
|
|
5178
|
+
const height = readItemHeight(currentIndex);
|
|
5179
|
+
if (height > 0) remaining += height;
|
|
5180
|
+
continue;
|
|
5181
|
+
}
|
|
5182
|
+
const height = readItemHeight(currentIndex);
|
|
5183
|
+
if (height > 0) {
|
|
5184
|
+
if (remaining <= height) return currentIndex + remaining / height;
|
|
5185
|
+
remaining -= height;
|
|
5186
|
+
} else if (remaining === 0) return currentIndex;
|
|
5187
|
+
if (currentIndex === itemCount - 1) return itemCount;
|
|
5188
|
+
currentIndex += 1;
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
function getTargetAnchorForItem(itemCount, index, block, anchorMode, viewportHeight, readItemHeight) {
|
|
5192
|
+
if (itemCount <= 0) return 0;
|
|
5193
|
+
const targetIndex = clampItemIndex(index, itemCount);
|
|
5194
|
+
const height = readItemHeight(targetIndex);
|
|
5195
|
+
if (anchorMode === "top") switch (block) {
|
|
5196
|
+
case "start": return getAnchorAtOffset(itemCount, targetIndex, 0, readItemHeight);
|
|
5197
|
+
case "center": return getAnchorAtOffset(itemCount, targetIndex, height / 2 - viewportHeight / 2, readItemHeight);
|
|
5198
|
+
case "end": return getAnchorAtOffset(itemCount, targetIndex, height - viewportHeight, readItemHeight);
|
|
5199
|
+
}
|
|
5200
|
+
switch (block) {
|
|
5201
|
+
case "start": return getAnchorAtOffset(itemCount, targetIndex, viewportHeight, readItemHeight);
|
|
5202
|
+
case "center": return getAnchorAtOffset(itemCount, targetIndex, height / 2 + viewportHeight / 2, readItemHeight);
|
|
5203
|
+
case "end": return getAnchorAtOffset(itemCount, targetIndex, height, readItemHeight);
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
//#endregion
|
|
4418
5207
|
//#region src/renderer/virtualized/solver.ts
|
|
4419
|
-
function clamp
|
|
5208
|
+
function clamp(value, min, max) {
|
|
4420
5209
|
return Math.min(Math.max(value, min), max);
|
|
4421
5210
|
}
|
|
4422
5211
|
function normalizeOffset(offset) {
|
|
4423
5212
|
return Number.isFinite(offset) ? offset : 0;
|
|
4424
5213
|
}
|
|
4425
|
-
function
|
|
5214
|
+
function resolveListLayoutOptions(options = {}) {
|
|
5215
|
+
return {
|
|
5216
|
+
anchorMode: options.anchorMode ?? "top",
|
|
5217
|
+
underflowAlign: options.underflowAlign ?? "top"
|
|
5218
|
+
};
|
|
5219
|
+
}
|
|
5220
|
+
function normalizeVisibleState(itemCount, state, layout) {
|
|
4426
5221
|
if (itemCount <= 0) return {
|
|
4427
5222
|
position: 0,
|
|
4428
5223
|
offset: 0
|
|
4429
5224
|
};
|
|
4430
5225
|
const position = state.position;
|
|
4431
|
-
const fallbackPosition =
|
|
5226
|
+
const fallbackPosition = layout.anchorMode === "top" ? 0 : itemCount - 1;
|
|
4432
5227
|
if (typeof position !== "number" || !Number.isFinite(position)) return {
|
|
4433
5228
|
position: fallbackPosition,
|
|
4434
5229
|
offset: normalizeOffset(state.offset)
|
|
4435
5230
|
};
|
|
4436
5231
|
return {
|
|
4437
|
-
position: clamp
|
|
5232
|
+
position: clamp(Math.trunc(position), 0, itemCount - 1),
|
|
4438
5233
|
offset: normalizeOffset(state.offset)
|
|
4439
5234
|
};
|
|
4440
5235
|
}
|
|
4441
|
-
function
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
const normalizedState = normalizeVisibleState(items.length, state, direction);
|
|
5236
|
+
function resolveVisibleWindow(items, state, viewportHeight, resolveItem, layout) {
|
|
5237
|
+
const normalizedState = normalizeVisibleState(items.length, state, layout);
|
|
5238
|
+
const resolutionPath = /* @__PURE__ */ new Set();
|
|
5239
|
+
const readResolvedItem = (item, idx) => {
|
|
5240
|
+
resolutionPath.add(idx);
|
|
5241
|
+
return resolveItem(item, idx);
|
|
5242
|
+
};
|
|
4449
5243
|
if (items.length === 0) return {
|
|
4450
5244
|
normalizedState,
|
|
5245
|
+
resolutionPath: [],
|
|
4451
5246
|
window: {
|
|
4452
5247
|
drawList: [],
|
|
4453
5248
|
shift: 0
|
|
4454
5249
|
}
|
|
4455
5250
|
};
|
|
4456
|
-
if (
|
|
5251
|
+
if (layout.anchorMode === "top") {
|
|
4457
5252
|
let { position, offset } = normalizedState;
|
|
4458
5253
|
let drawLength = 0;
|
|
4459
5254
|
if (offset > 0) if (position === 0) offset = 0;
|
|
4460
5255
|
else {
|
|
4461
5256
|
for (let i = position - 1; i >= 0; i -= 1) {
|
|
4462
|
-
const { height } =
|
|
5257
|
+
const { height } = readResolvedItem(items[i], i);
|
|
4463
5258
|
position = i;
|
|
4464
5259
|
offset -= height;
|
|
4465
5260
|
if (offset <= 0) break;
|
|
@@ -4469,7 +5264,7 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4469
5264
|
let y = offset;
|
|
4470
5265
|
const drawList = [];
|
|
4471
5266
|
for (let i = position; i < items.length; i += 1) {
|
|
4472
|
-
const { value, height } =
|
|
5267
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4473
5268
|
if (y + height > 0) {
|
|
4474
5269
|
drawList.push({
|
|
4475
5270
|
idx: i,
|
|
@@ -4494,7 +5289,7 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4494
5289
|
y = offset += shift;
|
|
4495
5290
|
let lastIdx = -1;
|
|
4496
5291
|
for (let i = position - 1; i >= 0; i -= 1) {
|
|
4497
|
-
const { value, height } =
|
|
5292
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4498
5293
|
drawLength += height;
|
|
4499
5294
|
y -= height;
|
|
4500
5295
|
drawList.push({
|
|
@@ -4512,22 +5307,19 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4512
5307
|
offset = 0;
|
|
4513
5308
|
}
|
|
4514
5309
|
}
|
|
4515
|
-
return {
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
shift
|
|
4523
|
-
}
|
|
4524
|
-
};
|
|
5310
|
+
return finalizeVisibleWindowResult(items.length, viewportHeight, layout, {
|
|
5311
|
+
position,
|
|
5312
|
+
offset
|
|
5313
|
+
}, Array.from(resolutionPath), {
|
|
5314
|
+
drawList,
|
|
5315
|
+
shift
|
|
5316
|
+
});
|
|
4525
5317
|
}
|
|
4526
5318
|
let { position, offset } = normalizedState;
|
|
4527
5319
|
let drawLength = 0;
|
|
4528
5320
|
if (offset < 0) if (position === items.length - 1) offset = 0;
|
|
4529
5321
|
else for (let i = position + 1; i < items.length; i += 1) {
|
|
4530
|
-
const { height } =
|
|
5322
|
+
const { height } = readResolvedItem(items[i], i);
|
|
4531
5323
|
position = i;
|
|
4532
5324
|
offset += height;
|
|
4533
5325
|
if (offset > 0) break;
|
|
@@ -4535,7 +5327,7 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4535
5327
|
let y = viewportHeight + offset;
|
|
4536
5328
|
const drawList = [];
|
|
4537
5329
|
for (let i = position; i >= 0; i -= 1) {
|
|
4538
|
-
const { value, height } =
|
|
5330
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4539
5331
|
y -= height;
|
|
4540
5332
|
if (y <= viewportHeight) {
|
|
4541
5333
|
drawList.push({
|
|
@@ -4557,7 +5349,7 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4557
5349
|
if (drawLength < viewportHeight) {
|
|
4558
5350
|
y = drawLength;
|
|
4559
5351
|
for (let i = position + 1; i < items.length; i += 1) {
|
|
4560
|
-
const { value, height } =
|
|
5352
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4561
5353
|
drawList.push({
|
|
4562
5354
|
idx: i,
|
|
4563
5355
|
value,
|
|
@@ -4571,122 +5363,88 @@ function resolveVisibleWindow(items, state, viewportHeight, resolveItem, directi
|
|
|
4571
5363
|
offset = drawLength < viewportHeight ? 0 : drawLength - viewportHeight;
|
|
4572
5364
|
} else offset = drawLength - viewportHeight;
|
|
4573
5365
|
}
|
|
5366
|
+
return finalizeVisibleWindowResult(items.length, viewportHeight, layout, {
|
|
5367
|
+
position,
|
|
5368
|
+
offset
|
|
5369
|
+
}, Array.from(resolutionPath), {
|
|
5370
|
+
drawList,
|
|
5371
|
+
shift
|
|
5372
|
+
});
|
|
5373
|
+
}
|
|
5374
|
+
function finalizeVisibleWindowResult(itemCount, viewportHeight, layout, normalizedState, resolutionPath, window) {
|
|
5375
|
+
if (window.drawList.length !== itemCount || itemCount <= 0) return {
|
|
5376
|
+
normalizedState,
|
|
5377
|
+
resolutionPath,
|
|
5378
|
+
window
|
|
5379
|
+
};
|
|
5380
|
+
let minIndex = Number.POSITIVE_INFINITY;
|
|
5381
|
+
let maxIndex = Number.NEGATIVE_INFINITY;
|
|
5382
|
+
let minOffset = Number.POSITIVE_INFINITY;
|
|
5383
|
+
let maxBottom = Number.NEGATIVE_INFINITY;
|
|
5384
|
+
for (const entry of window.drawList) {
|
|
5385
|
+
minIndex = Math.min(minIndex, entry.idx);
|
|
5386
|
+
maxIndex = Math.max(maxIndex, entry.idx);
|
|
5387
|
+
minOffset = Math.min(minOffset, entry.offset);
|
|
5388
|
+
maxBottom = Math.max(maxBottom, entry.offset + entry.height);
|
|
5389
|
+
}
|
|
5390
|
+
const contentHeight = maxBottom - minOffset;
|
|
5391
|
+
if (minIndex !== 0 || maxIndex !== itemCount - 1 || !(contentHeight < viewportHeight - Number.EPSILON)) return {
|
|
5392
|
+
normalizedState,
|
|
5393
|
+
resolutionPath,
|
|
5394
|
+
window
|
|
5395
|
+
};
|
|
5396
|
+
const desiredTop = layout.underflowAlign === "bottom" ? viewportHeight - contentHeight : 0;
|
|
4574
5397
|
return {
|
|
4575
|
-
normalizedState: {
|
|
4576
|
-
position,
|
|
4577
|
-
offset
|
|
5398
|
+
normalizedState: layout.anchorMode === "top" ? {
|
|
5399
|
+
position: 0,
|
|
5400
|
+
offset: 0
|
|
5401
|
+
} : {
|
|
5402
|
+
position: itemCount - 1,
|
|
5403
|
+
offset: 0
|
|
4578
5404
|
},
|
|
5405
|
+
resolutionPath,
|
|
4579
5406
|
window: {
|
|
4580
|
-
drawList,
|
|
4581
|
-
shift
|
|
5407
|
+
drawList: window.drawList,
|
|
5408
|
+
shift: desiredTop - minOffset
|
|
4582
5409
|
}
|
|
4583
5410
|
};
|
|
4584
5411
|
}
|
|
4585
|
-
function resolveTimelineVisibleWindow(items, state, viewportHeight, resolveItem) {
|
|
4586
|
-
return resolveVisibleWindow(items, state, viewportHeight, resolveItem, "forward");
|
|
4587
|
-
}
|
|
4588
|
-
function resolveChatVisibleWindow(items, state, viewportHeight, resolveItem) {
|
|
4589
|
-
return resolveVisibleWindow(items, state, viewportHeight, resolveItem, "backward");
|
|
4590
|
-
}
|
|
4591
5412
|
//#endregion
|
|
4592
|
-
//#region src/renderer/virtualized/
|
|
4593
|
-
function clamp$1(value, min, max) {
|
|
4594
|
-
return Math.min(Math.max(value, min), max);
|
|
4595
|
-
}
|
|
5413
|
+
//#region src/renderer/virtualized/list.ts
|
|
4596
5414
|
/**
|
|
4597
|
-
* Virtualized renderer
|
|
5415
|
+
* Virtualized list renderer with configurable anchor semantics.
|
|
4598
5416
|
*/
|
|
4599
|
-
var
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
}
|
|
4605
|
-
_getDefaultJumpBlock() {
|
|
4606
|
-
return "end";
|
|
4607
|
-
}
|
|
4608
|
-
_normalizeListState(state) {
|
|
4609
|
-
return normalizeChatState(this.items.length, state);
|
|
4610
|
-
}
|
|
4611
|
-
_readAnchor(state) {
|
|
4612
|
-
if (this.items.length === 0) return 0;
|
|
4613
|
-
const height = this._getItemHeight(state.position);
|
|
4614
|
-
return height > 0 ? state.position + 1 - state.offset / height : state.position + 1;
|
|
4615
|
-
}
|
|
4616
|
-
_applyAnchor(anchor) {
|
|
4617
|
-
if (this.items.length === 0) return;
|
|
4618
|
-
const clampedAnchor = clamp$1(anchor, 0, this.items.length);
|
|
4619
|
-
const position = clamp$1(Math.ceil(clampedAnchor) - 1, 0, this.items.length - 1);
|
|
4620
|
-
const height = this._getItemHeight(position);
|
|
4621
|
-
const offset = height > 0 ? (position + 1 - clampedAnchor) * height : 0;
|
|
4622
|
-
this._commitListState({
|
|
4623
|
-
position,
|
|
4624
|
-
offset: Object.is(offset, -0) ? 0 : offset
|
|
4625
|
-
});
|
|
4626
|
-
}
|
|
4627
|
-
_getTargetAnchor(index, block) {
|
|
4628
|
-
const height = this._getItemHeight(index);
|
|
4629
|
-
const viewportHeight = this.graphics.canvas.clientHeight;
|
|
4630
|
-
switch (block) {
|
|
4631
|
-
case "start": return this._getAnchorAtOffset(index, viewportHeight);
|
|
4632
|
-
case "center": return this._getAnchorAtOffset(index, height / 2 + viewportHeight / 2);
|
|
4633
|
-
case "end": return this._getAnchorAtOffset(index, height);
|
|
4634
|
-
}
|
|
5417
|
+
var ListRenderer = class extends VirtualizedRenderer {
|
|
5418
|
+
#layout;
|
|
5419
|
+
constructor(graphics, options) {
|
|
5420
|
+
super(graphics, options);
|
|
5421
|
+
this.#layout = resolveListLayoutOptions(options);
|
|
4635
5422
|
}
|
|
4636
|
-
|
|
4637
|
-
return
|
|
5423
|
+
_getLayoutOptions() {
|
|
5424
|
+
return this.#layout;
|
|
4638
5425
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
//#region src/renderer/virtualized/timeline.ts
|
|
4642
|
-
function clamp(value, min, max) {
|
|
4643
|
-
return Math.min(Math.max(value, min), max);
|
|
4644
|
-
}
|
|
4645
|
-
/**
|
|
4646
|
-
* Virtualized renderer anchored to the top, suitable for timeline-style UIs.
|
|
4647
|
-
*/
|
|
4648
|
-
var TimelineRenderer = class extends VirtualizedRenderer {
|
|
4649
|
-
_resolveVisibleWindow(now) {
|
|
4650
|
-
return resolveTimelineVisibleWindow(this.items, this._readListState(), this.graphics.canvas.clientHeight, (item, idx) => {
|
|
4651
|
-
return this._resolveItem(item, idx, now);
|
|
4652
|
-
});
|
|
5426
|
+
_resolveVisibleWindowForState(state, now) {
|
|
5427
|
+
return resolveVisibleWindow(this.items, state, this.graphics.canvas.clientHeight, (item, idx) => this._resolveItem(item, idx, now), this.#layout);
|
|
4653
5428
|
}
|
|
4654
5429
|
_getDefaultJumpBlock() {
|
|
4655
|
-
return "start";
|
|
5430
|
+
return this.#layout.anchorMode === "top" ? "start" : "end";
|
|
4656
5431
|
}
|
|
4657
5432
|
_normalizeListState(state) {
|
|
4658
|
-
return
|
|
5433
|
+
return normalizeVisibleState(this.items.length, state, this.#layout);
|
|
4659
5434
|
}
|
|
4660
|
-
_readAnchor(state) {
|
|
4661
|
-
|
|
4662
|
-
const height = this._getItemHeight(state.position);
|
|
4663
|
-
return height > 0 ? state.position - state.offset / height : state.position;
|
|
5435
|
+
_readAnchor(state, readItemHeight) {
|
|
5436
|
+
return readAnchorFromState(this.items.length, state, this.#layout.anchorMode, readItemHeight);
|
|
4664
5437
|
}
|
|
4665
5438
|
_applyAnchor(anchor) {
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
const height = this._getItemHeight(position);
|
|
4670
|
-
const offset = height > 0 ? -(clampedAnchor - position) * height : 0;
|
|
4671
|
-
this._commitListState({
|
|
4672
|
-
position,
|
|
4673
|
-
offset: Object.is(offset, -0) ? 0 : offset
|
|
4674
|
-
});
|
|
5439
|
+
const state = applyAnchorToState(this.items.length, anchor, this.#layout.anchorMode, this._getItemHeight.bind(this));
|
|
5440
|
+
if (state == null) return;
|
|
5441
|
+
this._commitListState(state);
|
|
4675
5442
|
}
|
|
4676
5443
|
_getTargetAnchor(index, block) {
|
|
4677
|
-
|
|
4678
|
-
const viewportHeight = this.graphics.canvas.clientHeight;
|
|
4679
|
-
switch (block) {
|
|
4680
|
-
case "start": return this._getAnchorAtOffset(index, 0);
|
|
4681
|
-
case "center": return this._getAnchorAtOffset(index, height / 2 - viewportHeight / 2);
|
|
4682
|
-
case "end": return this._getAnchorAtOffset(index, height - viewportHeight);
|
|
4683
|
-
}
|
|
4684
|
-
}
|
|
4685
|
-
_getAnimatedLayerOffset(_slotHeight, _nodeHeight) {
|
|
4686
|
-
return 0;
|
|
5444
|
+
return getTargetAnchorForItem(this.items.length, index, block, this.#layout.anchorMode, this.graphics.canvas.clientHeight, this._getItemHeight.bind(this));
|
|
4687
5445
|
}
|
|
4688
5446
|
};
|
|
4689
5447
|
//#endregion
|
|
4690
|
-
export { BaseRenderer,
|
|
5448
|
+
export { BaseRenderer, DebugRenderer, Fixed, Flex, FlexItem, Group, ListRenderer, ListState, MultilineText, PaddingBox, Place, ShrinkWrap, Text, VirtualizedRenderer, Wrapper, memoRenderItem, memoRenderItemBy };
|
|
4691
5449
|
|
|
4692
5450
|
//# sourceMappingURL=index.mjs.map
|