chat-layout 1.2.0 → 1.3.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example/chat.ts +3 -3
- package/index.d.mts +25 -30
- package/index.mjs +81 -24
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/example/chat.ts
CHANGED
|
@@ -673,17 +673,17 @@ button("push", () => {
|
|
|
673
673
|
});
|
|
674
674
|
|
|
675
675
|
button("jump middle", () => {
|
|
676
|
-
|
|
676
|
+
list.scrollTo(Math.floor(list.items.length / 2));
|
|
677
677
|
});
|
|
678
678
|
|
|
679
679
|
button("jump middle (center)", () => {
|
|
680
|
-
|
|
680
|
+
list.scrollTo(Math.floor(list.items.length / 2), {
|
|
681
681
|
block: "center",
|
|
682
682
|
});
|
|
683
683
|
});
|
|
684
684
|
|
|
685
685
|
button("jump latest (no anim)", () => {
|
|
686
|
-
|
|
686
|
+
list.scrollTo(list.items.length - 1, {
|
|
687
687
|
animated: false,
|
|
688
688
|
});
|
|
689
689
|
});
|
package/index.d.mts
CHANGED
|
@@ -533,6 +533,16 @@ interface InsertListItemsAnimationOptions {
|
|
|
533
533
|
}
|
|
534
534
|
type PushListItemsAnimationOptions = InsertListItemsAnimationOptions;
|
|
535
535
|
type UnshiftListItemsAnimationOptions = InsertListItemsAnimationOptions;
|
|
536
|
+
interface ScrollToOptions {
|
|
537
|
+
/** Whether to animate the jump. Defaults to `true`. */
|
|
538
|
+
animated?: boolean;
|
|
539
|
+
/** Which edge of the item should align with the viewport. */
|
|
540
|
+
block?: "start" | "center" | "end";
|
|
541
|
+
/** Animation duration in milliseconds. */
|
|
542
|
+
duration?: number;
|
|
543
|
+
/** Called after the scroll completes or finishes animating. */
|
|
544
|
+
onComplete?: () => void;
|
|
545
|
+
}
|
|
536
546
|
type ListScrollMutationSource = "external" | "internal";
|
|
537
547
|
type ListScrollStatePatch = {
|
|
538
548
|
position?: number | undefined;
|
|
@@ -580,6 +590,16 @@ declare class ListState<T extends {}> {
|
|
|
580
590
|
reset(items?: T[]): void;
|
|
581
591
|
/** Applies a relative pixel scroll delta. */
|
|
582
592
|
applyScroll(delta: number): void;
|
|
593
|
+
/** Scrolls the viewport to the requested item index. */
|
|
594
|
+
scrollTo(index: number, options?: ScrollToOptions): void;
|
|
595
|
+
/**
|
|
596
|
+
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
597
|
+
*/
|
|
598
|
+
scrollToTop(options?: ScrollToOptions): void;
|
|
599
|
+
/**
|
|
600
|
+
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
601
|
+
*/
|
|
602
|
+
scrollToBottom(options?: ScrollToOptions): void;
|
|
583
603
|
[WRITE_LIST_SCROLL_STATE](patch: ListScrollStatePatch, source: ListScrollMutationSource): void;
|
|
584
604
|
}
|
|
585
605
|
//#endregion
|
|
@@ -665,19 +685,6 @@ type VirtualizedResolvedItem = {
|
|
|
665
685
|
};
|
|
666
686
|
//#endregion
|
|
667
687
|
//#region src/renderer/virtualized/base.d.ts
|
|
668
|
-
/**
|
|
669
|
-
* Options for programmatic scrolling to a target item.
|
|
670
|
-
*/
|
|
671
|
-
interface JumpToOptions {
|
|
672
|
-
/** Whether to animate the jump. Defaults to `true`. */
|
|
673
|
-
animated?: boolean;
|
|
674
|
-
/** Which edge of the item should align with the viewport. */
|
|
675
|
-
block?: "start" | "center" | "end";
|
|
676
|
-
/** Animation duration in milliseconds. */
|
|
677
|
-
duration?: number;
|
|
678
|
-
/** Called after the jump completes or finishes animating. */
|
|
679
|
-
onComplete?: () => void;
|
|
680
|
-
}
|
|
681
688
|
/**
|
|
682
689
|
* Shared base class for virtualized list renderers.
|
|
683
690
|
*/
|
|
@@ -712,18 +719,6 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
712
719
|
protected _readListState(): VisibleListState;
|
|
713
720
|
protected _resolveVisibleWindow(now: number): VisibleWindowResult<VirtualizedResolvedItem>;
|
|
714
721
|
protected _commitListState(state: NormalizedListState): void;
|
|
715
|
-
/**
|
|
716
|
-
* Scrolls the viewport to the requested item index.
|
|
717
|
-
*/
|
|
718
|
-
jumpTo(index: number, options?: JumpToOptions): void;
|
|
719
|
-
/**
|
|
720
|
-
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
721
|
-
*/
|
|
722
|
-
jumpToTop(options?: JumpToOptions): void;
|
|
723
|
-
/**
|
|
724
|
-
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
725
|
-
*/
|
|
726
|
-
jumpToBottom(options?: JumpToOptions): void;
|
|
727
722
|
protected _resetRenderFeedback(feedback?: RenderFeedback): void;
|
|
728
723
|
protected _accumulateRenderFeedback(feedback: RenderFeedback, idx: number, top: number, height: number): void;
|
|
729
724
|
protected _renderDrawList(list: VisibleWindow<VirtualizedResolvedItem>["drawList"], shift: number, feedback?: RenderFeedback): boolean;
|
|
@@ -756,8 +751,8 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
756
751
|
protected abstract _resolveVisibleWindowForState(state: VisibleListState, now: number): VisibleWindowResult<VirtualizedResolvedItem>;
|
|
757
752
|
protected abstract _readAnchor(state: NormalizedListState, readItemHeight: (index: number) => number): number;
|
|
758
753
|
protected abstract _applyAnchor(anchor: number): void;
|
|
759
|
-
protected abstract _getDefaultJumpBlock(): NonNullable<
|
|
760
|
-
protected abstract _getTargetAnchor(index: number, block: NonNullable<
|
|
754
|
+
protected abstract _getDefaultJumpBlock(): NonNullable<ScrollToOptions["block"]>;
|
|
755
|
+
protected abstract _getTargetAnchor(index: number, block: NonNullable<ScrollToOptions["block"]>): number;
|
|
761
756
|
protected _getViewportMetrics(): ListViewportMetrics;
|
|
762
757
|
}
|
|
763
758
|
//#endregion
|
|
@@ -776,12 +771,12 @@ declare class ListRenderer<C extends CanvasRenderingContext2D, T extends {}> ext
|
|
|
776
771
|
set padding(value: ListPadding);
|
|
777
772
|
protected _getLayoutOptions(): ResolvedListLayoutOptions;
|
|
778
773
|
protected _resolveVisibleWindowForState(state: VisibleListState, now: number): VisibleWindowResult<VirtualizedResolvedItem>;
|
|
779
|
-
protected _getDefaultJumpBlock(): NonNullable<
|
|
774
|
+
protected _getDefaultJumpBlock(): NonNullable<ScrollToOptions["block"]>;
|
|
780
775
|
protected _normalizeListState(state: VisibleListState): NormalizedListState;
|
|
781
776
|
protected _readAnchor(state: NormalizedListState, readItemHeight: (index: number) => number): number;
|
|
782
777
|
protected _applyAnchor(anchor: number): void;
|
|
783
|
-
protected _getTargetAnchor(index: number, block: NonNullable<
|
|
778
|
+
protected _getTargetAnchor(index: number, block: NonNullable<ScrollToOptions["block"]>): number;
|
|
784
779
|
}
|
|
785
780
|
//#endregion
|
|
786
|
-
export { Axis, BaseRenderer, Box, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DeleteListItemAnimationOptions, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, InlineSpan, InsertListItemsAnimationOptions,
|
|
781
|
+
export { Axis, BaseRenderer, Box, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DeleteListItemAnimationOptions, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, InlineSpan, InsertListItemsAnimationOptions, LayoutConstraints, LayoutRect, ListAnchorMode, ListLayoutOptions, ListPadding, ListRenderer, ListRendererOptions, ListState, ListUnderflowAlign, MainAxisAlignment, MainAxisSize, MultilineText, MultilineTextOptions, Node, PaddingBox, PhysicalTextAlign, Place, PushListItemsAnimationOptions, RenderFeedback, RendererOptions, ScrollToOptions, ShrinkWrap, Text, TextAlign, TextEllipsisPosition, TextJustifyMode, TextJustifyOptions, TextOptions, TextOverflowMode, TextOverflowWrapMode, TextStyleOptions, TextWhiteSpaceMode, TextWordBreakMode, UnshiftListItemsAnimationOptions, UpdateListItemAnimationOptions, VirtualizedRenderer, Wrapper, initRenderFeedback, memoRenderItem, memoRenderItemBy };
|
|
787
782
|
//# sourceMappingURL=index.d.mts.map
|
package/index.mjs
CHANGED
|
@@ -3576,11 +3576,13 @@ var DebugRenderer = class extends BaseRenderer {
|
|
|
3576
3576
|
//#endregion
|
|
3577
3577
|
//#region src/renderer/list-state.ts
|
|
3578
3578
|
const listStateChangeQueues = /* @__PURE__ */ new WeakMap();
|
|
3579
|
+
const listScrollCommandQueues = /* @__PURE__ */ new WeakMap();
|
|
3579
3580
|
const listScrollMutations = /* @__PURE__ */ new WeakMap();
|
|
3580
3581
|
const WRITE_LIST_SCROLL_STATE = Symbol("writeListScrollState");
|
|
3581
3582
|
const FINALIZE_LIST_DELETE = Symbol("finalizeListDelete");
|
|
3582
3583
|
const LIST_STATE_CHANGE_TIME = Symbol("listStateChangeTime");
|
|
3583
3584
|
const LIST_STATE_CHANGE_SNAPSHOT = Symbol("listStateChangeSnapshot");
|
|
3585
|
+
const LIST_SCROLL_COMMAND_TIME = Symbol("listScrollCommandTime");
|
|
3584
3586
|
function normalizePosition(value) {
|
|
3585
3587
|
return typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : void 0;
|
|
3586
3588
|
}
|
|
@@ -3616,6 +3618,14 @@ function writeInternalListScrollState(list, state) {
|
|
|
3616
3618
|
function finalizeInternalListDelete(list, item) {
|
|
3617
3619
|
list[FINALIZE_LIST_DELETE](item);
|
|
3618
3620
|
}
|
|
3621
|
+
function normalizeScrollToOptions(options) {
|
|
3622
|
+
const normalized = {};
|
|
3623
|
+
if (typeof options?.animated === "boolean") normalized.animated = options.animated;
|
|
3624
|
+
if (options?.block === "start" || options?.block === "center" || options?.block === "end") normalized.block = options.block;
|
|
3625
|
+
if (options?.duration != null && Number.isFinite(options.duration)) normalized.duration = options.duration;
|
|
3626
|
+
if (typeof options?.onComplete === "function") normalized.onComplete = options.onComplete;
|
|
3627
|
+
return normalized;
|
|
3628
|
+
}
|
|
3619
3629
|
function enqueueListStateChange(list, change) {
|
|
3620
3630
|
const key = list;
|
|
3621
3631
|
let queue = listStateChangeQueues.get(key);
|
|
@@ -3638,6 +3648,20 @@ function enqueueListStateChange(list, change) {
|
|
|
3638
3648
|
});
|
|
3639
3649
|
queue.push(timestampedChange);
|
|
3640
3650
|
}
|
|
3651
|
+
function enqueueListScrollCommand(list, command) {
|
|
3652
|
+
const key = list;
|
|
3653
|
+
let queue = listScrollCommandQueues.get(key);
|
|
3654
|
+
if (queue == null) {
|
|
3655
|
+
queue = [];
|
|
3656
|
+
listScrollCommandQueues.set(key, queue);
|
|
3657
|
+
}
|
|
3658
|
+
const timestampedCommand = command;
|
|
3659
|
+
Object.defineProperty(timestampedCommand, LIST_SCROLL_COMMAND_TIME, {
|
|
3660
|
+
value: performance.now(),
|
|
3661
|
+
configurable: true
|
|
3662
|
+
});
|
|
3663
|
+
queue.push(timestampedCommand);
|
|
3664
|
+
}
|
|
3641
3665
|
function drainInternalListStateChanges(list) {
|
|
3642
3666
|
const key = list;
|
|
3643
3667
|
const queue = listStateChangeQueues.get(key);
|
|
@@ -3645,12 +3669,22 @@ function drainInternalListStateChanges(list) {
|
|
|
3645
3669
|
listStateChangeQueues.delete(key);
|
|
3646
3670
|
return queue;
|
|
3647
3671
|
}
|
|
3672
|
+
function drainInternalListScrollCommands(list) {
|
|
3673
|
+
const key = list;
|
|
3674
|
+
const queue = listScrollCommandQueues.get(key);
|
|
3675
|
+
if (queue == null || queue.length === 0) return [];
|
|
3676
|
+
listScrollCommandQueues.delete(key);
|
|
3677
|
+
return queue;
|
|
3678
|
+
}
|
|
3648
3679
|
function readInternalListStateChangeTime(change) {
|
|
3649
3680
|
return change[LIST_STATE_CHANGE_TIME];
|
|
3650
3681
|
}
|
|
3651
3682
|
function readInternalListStateChangeSnapshot(change) {
|
|
3652
3683
|
return change[LIST_STATE_CHANGE_SNAPSHOT];
|
|
3653
3684
|
}
|
|
3685
|
+
function readInternalListScrollCommandTime(command) {
|
|
3686
|
+
return command[LIST_SCROLL_COMMAND_TIME];
|
|
3687
|
+
}
|
|
3654
3688
|
function isObjectIdentityCandidate(value) {
|
|
3655
3689
|
return typeof value === "object" && value !== null || typeof value === "function";
|
|
3656
3690
|
}
|
|
@@ -3834,6 +3868,34 @@ var ListState = class {
|
|
|
3834
3868
|
applyScroll(delta) {
|
|
3835
3869
|
this.#writeScrollState({ offset: this.#offset + delta }, "external");
|
|
3836
3870
|
}
|
|
3871
|
+
/** Scrolls the viewport to the requested item index. */
|
|
3872
|
+
scrollTo(index, options = {}) {
|
|
3873
|
+
enqueueListScrollCommand(this, {
|
|
3874
|
+
type: "index",
|
|
3875
|
+
index,
|
|
3876
|
+
options: normalizeScrollToOptions(options)
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
/**
|
|
3880
|
+
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
3881
|
+
*/
|
|
3882
|
+
scrollToTop(options = {}) {
|
|
3883
|
+
enqueueListScrollCommand(this, {
|
|
3884
|
+
type: "boundary",
|
|
3885
|
+
boundary: "top",
|
|
3886
|
+
options: normalizeScrollToOptions(options)
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3889
|
+
/**
|
|
3890
|
+
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
3891
|
+
*/
|
|
3892
|
+
scrollToBottom(options = {}) {
|
|
3893
|
+
enqueueListScrollCommand(this, {
|
|
3894
|
+
type: "boundary",
|
|
3895
|
+
boundary: "bottom",
|
|
3896
|
+
options: normalizeScrollToOptions(options)
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3837
3899
|
[WRITE_LIST_SCROLL_STATE](patch, source) {
|
|
3838
3900
|
this.#writeScrollState(patch, source);
|
|
3839
3901
|
}
|
|
@@ -4112,16 +4174,16 @@ var JumpController = class JumpController {
|
|
|
4112
4174
|
commit(state) {
|
|
4113
4175
|
this.#lastHandledScrollMutationVersion = this.#options.readScrollMutation().version;
|
|
4114
4176
|
}
|
|
4115
|
-
jumpTo(index, options = {}) {
|
|
4177
|
+
jumpTo(index, options = {}, now = getNow()) {
|
|
4116
4178
|
this.#clearPendingTransitionSettleReconcile();
|
|
4117
4179
|
this.#clearPendingPostJumpBoundary();
|
|
4118
4180
|
if (this.#options.getItemCount() === 0) {
|
|
4119
4181
|
this.#cancelJumpAnimation();
|
|
4120
4182
|
return;
|
|
4121
4183
|
}
|
|
4122
|
-
this.#startJumpToIndex(index, options);
|
|
4184
|
+
this.#startJumpToIndex(index, options, now);
|
|
4123
4185
|
}
|
|
4124
|
-
jumpToBoundary(boundary, options = {}) {
|
|
4186
|
+
jumpToBoundary(boundary, options = {}, now = getNow()) {
|
|
4125
4187
|
this.#clearPendingTransitionSettleReconcile();
|
|
4126
4188
|
this.#clearPendingPostJumpBoundary();
|
|
4127
4189
|
this.#armAutoFollowBoundary(boundary, "jump-to-boundary");
|
|
@@ -4132,7 +4194,7 @@ var JumpController = class JumpController {
|
|
|
4132
4194
|
this.#startJumpToIndex(boundary === "bottom" ? this.#options.getItemCount() - 1 : 0, {
|
|
4133
4195
|
...options,
|
|
4134
4196
|
block: boundary === "bottom" ? "end" : "start"
|
|
4135
|
-
});
|
|
4197
|
+
}, now);
|
|
4136
4198
|
}
|
|
4137
4199
|
beginAutoFollowBoundaryObservation(boundary) {
|
|
4138
4200
|
if (boundary === "top") {
|
|
@@ -5404,8 +5466,9 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5404
5466
|
/** Renders the current visible window. */
|
|
5405
5467
|
render(feedback) {
|
|
5406
5468
|
this.#drainPendingListStateChanges();
|
|
5407
|
-
this.#jumpController.beforeFrame();
|
|
5408
5469
|
this.#jumpController.noteViewportWidth(this.graphics.canvas.clientWidth);
|
|
5470
|
+
this.#drainPendingListScrollCommands();
|
|
5471
|
+
this.#jumpController.beforeFrame();
|
|
5409
5472
|
const now = getNow();
|
|
5410
5473
|
const keepAnimating = this._prepareRender(now);
|
|
5411
5474
|
const { clientWidth: viewportWidth, clientHeight: viewportHeight } = this.graphics.canvas;
|
|
@@ -5428,8 +5491,9 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5428
5491
|
/** Hit-tests the current visible window. */
|
|
5429
5492
|
hittest(test) {
|
|
5430
5493
|
this.#drainPendingListStateChanges();
|
|
5431
|
-
this.#jumpController.beforeFrame();
|
|
5432
5494
|
this.#jumpController.noteViewportWidth(this.graphics.canvas.clientWidth);
|
|
5495
|
+
this.#drainPendingListScrollCommands();
|
|
5496
|
+
this.#jumpController.beforeFrame();
|
|
5433
5497
|
const now = getNow();
|
|
5434
5498
|
this.#transitionController.settle(now, this.#getTransitionLifecycleAdapter());
|
|
5435
5499
|
const frame = prepareFrameSession({
|
|
@@ -5454,24 +5518,6 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5454
5518
|
writeInternalListScrollState(this.options.list, state);
|
|
5455
5519
|
this.#jumpController.commit(state);
|
|
5456
5520
|
}
|
|
5457
|
-
/**
|
|
5458
|
-
* Scrolls the viewport to the requested item index.
|
|
5459
|
-
*/
|
|
5460
|
-
jumpTo(index, options = {}) {
|
|
5461
|
-
this.#jumpController.jumpTo(index, options);
|
|
5462
|
-
}
|
|
5463
|
-
/**
|
|
5464
|
-
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
5465
|
-
*/
|
|
5466
|
-
jumpToTop(options = {}) {
|
|
5467
|
-
this.#jumpController.jumpToBoundary("top", options);
|
|
5468
|
-
}
|
|
5469
|
-
/**
|
|
5470
|
-
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
5471
|
-
*/
|
|
5472
|
-
jumpToBottom(options = {}) {
|
|
5473
|
-
this.#jumpController.jumpToBoundary("bottom", options);
|
|
5474
|
-
}
|
|
5475
5521
|
_resetRenderFeedback(feedback) {
|
|
5476
5522
|
if (feedback == null) return;
|
|
5477
5523
|
initRenderFeedback(feedback);
|
|
@@ -5672,6 +5718,17 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5672
5718
|
for (const change of changes) this.#handleListStateChange(change, readInternalListStateChangeTime(change), readInternalListStateChangeSnapshot(change));
|
|
5673
5719
|
}
|
|
5674
5720
|
}
|
|
5721
|
+
#handleListScrollCommand(command, now) {
|
|
5722
|
+
if (command.type === "boundary") {
|
|
5723
|
+
this.#jumpController.jumpToBoundary(command.boundary, command.options, now);
|
|
5724
|
+
return;
|
|
5725
|
+
}
|
|
5726
|
+
this.#jumpController.jumpTo(command.index, command.options, now);
|
|
5727
|
+
}
|
|
5728
|
+
#drainPendingListScrollCommands() {
|
|
5729
|
+
const commands = drainInternalListScrollCommands(this.options.list);
|
|
5730
|
+
for (const command of commands) this.#handleListScrollCommand(command, readInternalListScrollCommandTime(command));
|
|
5731
|
+
}
|
|
5675
5732
|
};
|
|
5676
5733
|
//#endregion
|
|
5677
5734
|
//#region src/renderer/virtualized/anchor-model.ts
|