chat-layout 1.2.0-5 → 1.2.0-7
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 +2 -2
- package/example/chat.ts +19 -6
- package/index.d.mts +58 -9
- package/index.mjs +945 -488
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,11 +67,11 @@ list.unshiftAll([olderMessage], {
|
|
|
67
67
|
});
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
To make chat-style inserts automatically follow the latest visible edge, pass `
|
|
70
|
+
To make chat-style inserts automatically follow the latest visible edge, pass `autoFollow: true`. When the corresponding auto-follow latch is armed, the insert behaves like a conditional `jumpToTop()` / `jumpToBottom()` after the items are inserted:
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
73
|
list.pushAll([nextMessage], {
|
|
74
|
-
|
|
74
|
+
autoFollow: true,
|
|
75
75
|
duration: 220,
|
|
76
76
|
});
|
|
77
77
|
```
|
package/example/chat.ts
CHANGED
|
@@ -505,6 +505,7 @@ const renderer = new ListRenderer(ctx, {
|
|
|
505
505
|
renderItem,
|
|
506
506
|
list,
|
|
507
507
|
});
|
|
508
|
+
renderer.padding = { top: 32, bottom: 32 };
|
|
508
509
|
let nextMessageId = list.items.length + 1;
|
|
509
510
|
|
|
510
511
|
function drawFrame(): void {
|
|
@@ -513,19 +514,32 @@ function drawFrame(): void {
|
|
|
513
514
|
maxIdx: Number.NaN,
|
|
514
515
|
min: Number.NaN,
|
|
515
516
|
max: Number.NaN,
|
|
517
|
+
canAutoFollowTop: false,
|
|
518
|
+
canAutoFollowBottom: false,
|
|
516
519
|
};
|
|
517
520
|
renderer.render(feedback);
|
|
518
521
|
|
|
519
522
|
ctx.save();
|
|
523
|
+
|
|
524
|
+
ctx.fillStyle = "rgba(255, 0, 255, 0.5)";
|
|
525
|
+
ctx.fillRect(0, 0, canvas.clientWidth, 32);
|
|
526
|
+
ctx.fillRect(0, canvas.clientHeight - 32, canvas.clientWidth, 32);
|
|
527
|
+
|
|
520
528
|
ctx.textBaseline = "top";
|
|
521
529
|
ctx.font = "12px system-ui";
|
|
522
530
|
ctx.fillStyle = "black";
|
|
523
531
|
ctx.strokeStyle = "white";
|
|
524
532
|
ctx.lineWidth = 4;
|
|
525
533
|
ctx.lineJoin = "round";
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
534
|
+
const lines = Object.entries(feedback).map(
|
|
535
|
+
([key, value]) => `${key}: ${String(value)}`,
|
|
536
|
+
);
|
|
537
|
+
const lineHeight = 14;
|
|
538
|
+
for (const [index, line] of lines.entries()) {
|
|
539
|
+
const y = 10 + index * lineHeight;
|
|
540
|
+
ctx.strokeText(line, 10, y);
|
|
541
|
+
ctx.fillText(line, 10, y);
|
|
542
|
+
}
|
|
529
543
|
ctx.restore();
|
|
530
544
|
|
|
531
545
|
requestAnimationFrame(drawFrame);
|
|
@@ -644,7 +658,7 @@ button("unshift", () => {
|
|
|
644
658
|
],
|
|
645
659
|
{
|
|
646
660
|
duration: INSERT_ANIMATION_DURATION,
|
|
647
|
-
|
|
661
|
+
autoFollow: true,
|
|
648
662
|
},
|
|
649
663
|
);
|
|
650
664
|
});
|
|
@@ -660,8 +674,7 @@ button("push", () => {
|
|
|
660
674
|
},
|
|
661
675
|
],
|
|
662
676
|
{
|
|
663
|
-
|
|
664
|
-
followIfAtBoundary: true,
|
|
677
|
+
autoFollow: true,
|
|
665
678
|
},
|
|
666
679
|
);
|
|
667
680
|
});
|
package/index.d.mts
CHANGED
|
@@ -19,6 +19,10 @@ interface RenderFeedback {
|
|
|
19
19
|
min: number;
|
|
20
20
|
/** Largest visible continuous item position, expressed in item coordinates rather than pixels. */
|
|
21
21
|
max: number;
|
|
22
|
+
/** Whether the current viewport may auto-follow inserts at the visual top edge. */
|
|
23
|
+
canAutoFollowTop: boolean;
|
|
24
|
+
/** Whether the current viewport may auto-follow inserts at the visual bottom edge. */
|
|
25
|
+
canAutoFollowBottom: boolean;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
24
28
|
* The main axis direction used by flex containers.
|
|
@@ -520,19 +524,25 @@ interface DeleteListItemAnimationOptions {
|
|
|
520
524
|
interface InsertListItemsAnimationOptions {
|
|
521
525
|
/** Animation duration in milliseconds. */
|
|
522
526
|
duration?: number;
|
|
523
|
-
/** Enter offset in pixels measured from the final resting position. */
|
|
524
|
-
distance?: number;
|
|
525
527
|
/** Auto-follow the insertion edge when the viewport was already pinned there. */
|
|
526
|
-
|
|
528
|
+
autoFollow?: boolean;
|
|
527
529
|
}
|
|
528
530
|
type PushListItemsAnimationOptions = InsertListItemsAnimationOptions;
|
|
529
531
|
type UnshiftListItemsAnimationOptions = InsertListItemsAnimationOptions;
|
|
532
|
+
type ListScrollMutationSource = "external" | "internal";
|
|
533
|
+
type ListScrollStatePatch = {
|
|
534
|
+
position?: number | undefined;
|
|
535
|
+
offset?: number;
|
|
536
|
+
};
|
|
537
|
+
declare const WRITE_LIST_SCROLL_STATE: unique symbol;
|
|
530
538
|
declare class ListState<T extends {}> {
|
|
531
539
|
#private;
|
|
532
540
|
/** Pixel offset from the anchored item edge. */
|
|
533
|
-
offset: number;
|
|
541
|
+
get offset(): number;
|
|
542
|
+
set offset(value: number);
|
|
534
543
|
/** Anchor item index, or `undefined` to use the renderer default. */
|
|
535
|
-
position: number | undefined;
|
|
544
|
+
get position(): number | undefined;
|
|
545
|
+
set position(value: number | undefined);
|
|
536
546
|
/** Items currently managed by the renderer. */
|
|
537
547
|
get items(): T[];
|
|
538
548
|
/** Replaces the full item collection while preserving scroll state. */
|
|
@@ -573,6 +583,7 @@ declare class ListState<T extends {}> {
|
|
|
573
583
|
resetScroll(): void;
|
|
574
584
|
/** Applies a relative pixel scroll delta. */
|
|
575
585
|
applyScroll(delta: number): void;
|
|
586
|
+
[WRITE_LIST_SCROLL_STATE](patch: ListScrollStatePatch, source: ListScrollMutationSource): void;
|
|
576
587
|
}
|
|
577
588
|
//#endregion
|
|
578
589
|
//#region src/renderer/memo.d.ts
|
|
@@ -593,6 +604,10 @@ declare function memoRenderItemBy<C extends CanvasRenderingContext2D, T, K>(keyO
|
|
|
593
604
|
};
|
|
594
605
|
//#endregion
|
|
595
606
|
//#region src/renderer/virtualized/base-types.d.ts
|
|
607
|
+
type AutoFollowCapabilities = {
|
|
608
|
+
top: boolean;
|
|
609
|
+
bottom: boolean;
|
|
610
|
+
};
|
|
596
611
|
/** Per-item draw/hittest callbacks produced by the resolver. */
|
|
597
612
|
type VirtualizedResolvedItem = {
|
|
598
613
|
draw: (y: number) => boolean;
|
|
@@ -602,13 +617,31 @@ type VirtualizedResolvedItem = {
|
|
|
602
617
|
//#region src/renderer/virtualized/solver.d.ts
|
|
603
618
|
type ListAnchorMode = "top" | "bottom";
|
|
604
619
|
type ListUnderflowAlign = "top" | "bottom";
|
|
620
|
+
interface ListPadding {
|
|
621
|
+
top?: number;
|
|
622
|
+
bottom?: number;
|
|
623
|
+
}
|
|
624
|
+
interface ResolvedListPadding {
|
|
625
|
+
top: number;
|
|
626
|
+
bottom: number;
|
|
627
|
+
}
|
|
605
628
|
interface ListLayoutOptions {
|
|
606
629
|
anchorMode?: ListAnchorMode;
|
|
607
630
|
underflowAlign?: ListUnderflowAlign;
|
|
631
|
+
padding?: ListPadding;
|
|
608
632
|
}
|
|
609
633
|
interface ResolvedListLayoutOptions {
|
|
610
634
|
anchorMode: ListAnchorMode;
|
|
611
635
|
underflowAlign: ListUnderflowAlign;
|
|
636
|
+
padding: ResolvedListPadding;
|
|
637
|
+
}
|
|
638
|
+
interface ListViewportMetrics {
|
|
639
|
+
outerHeight: number;
|
|
640
|
+
contentTop: number;
|
|
641
|
+
contentBottom: number;
|
|
642
|
+
contentHeight: number;
|
|
643
|
+
outerContentTop: number;
|
|
644
|
+
outerContentBottom: number;
|
|
612
645
|
}
|
|
613
646
|
interface VisibleListState {
|
|
614
647
|
position?: number;
|
|
@@ -690,17 +723,30 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
690
723
|
* Scrolls the viewport to the requested item index.
|
|
691
724
|
*/
|
|
692
725
|
jumpTo(index: number, options?: JumpToOptions): void;
|
|
726
|
+
/**
|
|
727
|
+
* Scrolls the viewport to the visual top edge and arms top auto-follow immediately.
|
|
728
|
+
*/
|
|
729
|
+
jumpToTop(options?: JumpToOptions): void;
|
|
730
|
+
/**
|
|
731
|
+
* Scrolls the viewport to the visual bottom edge and arms bottom auto-follow immediately.
|
|
732
|
+
*/
|
|
733
|
+
jumpToBottom(options?: JumpToOptions): void;
|
|
693
734
|
protected _resetRenderFeedback(feedback?: RenderFeedback): void;
|
|
694
735
|
protected _accumulateRenderFeedback(feedback: RenderFeedback, idx: number, top: number, height: number): void;
|
|
695
736
|
protected _renderDrawList(list: VisibleWindow<VirtualizedResolvedItem>["drawList"], shift: number, feedback?: RenderFeedback): boolean;
|
|
696
|
-
protected _renderVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem>, feedback?: RenderFeedback
|
|
737
|
+
protected _renderVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem>, feedback?: RenderFeedback): boolean;
|
|
738
|
+
protected _readAutoFollowCapabilities(window: VisibleWindow<VirtualizedResolvedItem>): AutoFollowCapabilities;
|
|
697
739
|
protected _readVisibleRange(top: number, height: number): {
|
|
698
740
|
top: number;
|
|
699
741
|
bottom: number;
|
|
700
742
|
} | undefined;
|
|
743
|
+
protected _readOuterVisibleRange(top: number, height: number): {
|
|
744
|
+
top: number;
|
|
745
|
+
bottom: number;
|
|
746
|
+
} | undefined;
|
|
701
747
|
protected _pruneTransitionAnimations(_window: VisibleWindow<unknown>, now: number): boolean;
|
|
702
|
-
protected _hittestVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem>, test: HitTest
|
|
703
|
-
protected _captureVisibleItemSnapshot(solution: VisibleWindowResult<unknown
|
|
748
|
+
protected _hittestVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem>, test: HitTest): boolean;
|
|
749
|
+
protected _captureVisibleItemSnapshot(solution: VisibleWindowResult<unknown>): void;
|
|
704
750
|
protected _prepareRender(now: number): boolean;
|
|
705
751
|
protected _finishRender(requestRedraw: boolean): boolean;
|
|
706
752
|
protected _clampItemIndex(index: number): number;
|
|
@@ -719,6 +765,7 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
719
765
|
protected abstract _applyAnchor(anchor: number): void;
|
|
720
766
|
protected abstract _getDefaultJumpBlock(): NonNullable<JumpToOptions["block"]>;
|
|
721
767
|
protected abstract _getTargetAnchor(index: number, block: NonNullable<JumpToOptions["block"]>): number;
|
|
768
|
+
protected _getViewportMetrics(): ListViewportMetrics;
|
|
722
769
|
}
|
|
723
770
|
//#endregion
|
|
724
771
|
//#region src/renderer/virtualized/list.d.ts
|
|
@@ -732,6 +779,8 @@ interface ListRendererOptions<C extends CanvasRenderingContext2D, T extends {}>
|
|
|
732
779
|
declare class ListRenderer<C extends CanvasRenderingContext2D, T extends {}> extends VirtualizedRenderer<C, T> {
|
|
733
780
|
#private;
|
|
734
781
|
constructor(graphics: C, options: ListRendererOptions<C, T>);
|
|
782
|
+
get padding(): ListPadding;
|
|
783
|
+
set padding(value: ListPadding);
|
|
735
784
|
protected _getLayoutOptions(): ResolvedListLayoutOptions;
|
|
736
785
|
protected _resolveVisibleWindowForState(state: VisibleListState, now: number): VisibleWindowResult<VirtualizedResolvedItem>;
|
|
737
786
|
protected _getDefaultJumpBlock(): NonNullable<JumpToOptions["block"]>;
|
|
@@ -741,5 +790,5 @@ declare class ListRenderer<C extends CanvasRenderingContext2D, T extends {}> ext
|
|
|
741
790
|
protected _getTargetAnchor(index: number, block: NonNullable<JumpToOptions["block"]>): number;
|
|
742
791
|
}
|
|
743
792
|
//#endregion
|
|
744
|
-
export { Axis, BaseRenderer, Box, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DeleteListItemAnimationOptions, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, InlineSpan, InsertListItemsAnimationOptions, JumpToOptions, LayoutConstraints, LayoutRect, ListAnchorMode, ListLayoutOptions, ListRenderer, ListRendererOptions, ListState, ListUnderflowAlign, MainAxisAlignment, MainAxisSize, MultilineText, MultilineTextOptions, Node, PaddingBox, PhysicalTextAlign, Place, PushListItemsAnimationOptions, RenderFeedback, RendererOptions, ShrinkWrap, Text, TextAlign, TextEllipsisPosition, TextJustifyMode, TextJustifyOptions, TextOptions, TextOverflowMode, TextOverflowWrapMode, TextStyleOptions, TextWhiteSpaceMode, TextWordBreakMode, UnshiftListItemsAnimationOptions, UpdateListItemAnimationOptions, VirtualizedRenderer, Wrapper, memoRenderItem, memoRenderItemBy };
|
|
793
|
+
export { Axis, BaseRenderer, Box, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DeleteListItemAnimationOptions, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, InlineSpan, InsertListItemsAnimationOptions, JumpToOptions, LayoutConstraints, LayoutRect, ListAnchorMode, ListLayoutOptions, ListPadding, ListRenderer, ListRendererOptions, ListState, ListUnderflowAlign, MainAxisAlignment, MainAxisSize, MultilineText, MultilineTextOptions, Node, PaddingBox, PhysicalTextAlign, Place, PushListItemsAnimationOptions, RenderFeedback, RendererOptions, ShrinkWrap, Text, TextAlign, TextEllipsisPosition, TextJustifyMode, TextJustifyOptions, TextOptions, TextOverflowMode, TextOverflowWrapMode, TextStyleOptions, TextWhiteSpaceMode, TextWordBreakMode, UnshiftListItemsAnimationOptions, UpdateListItemAnimationOptions, VirtualizedRenderer, Wrapper, memoRenderItem, memoRenderItemBy };
|
|
745
794
|
//# sourceMappingURL=index.d.mts.map
|