feat(chat): implement pull-to-refresh functionality and pagination for chat history
This commit is contained in:
@@ -144,12 +144,47 @@ describe("ChatArea scrolling", () => {
|
||||
|
||||
expect(scrollNode.scrollTop).toBe(100);
|
||||
});
|
||||
|
||||
it("preserves the visible message after older history is prepended", () => {
|
||||
scrollHeight = 1_000;
|
||||
clientHeight = 300;
|
||||
const onLoadMoreHistory = vi.fn();
|
||||
const history = [createMessage("history-1")];
|
||||
renderChatArea(root, history, true, {
|
||||
canLoadMoreHistory: true,
|
||||
onLoadMoreHistory,
|
||||
});
|
||||
const scrollNode = getScrollNode(container);
|
||||
scrollNode.scrollTop = 0;
|
||||
act(() => scrollNode.dispatchEvent(new Event("scroll", { bubbles: true })));
|
||||
|
||||
pull(scrollNode, 180);
|
||||
expect(onLoadMoreHistory).toHaveBeenCalledOnce();
|
||||
|
||||
scrollHeight = 1_400;
|
||||
renderChatArea(
|
||||
root,
|
||||
[createMessage("older-1"), ...history],
|
||||
true,
|
||||
{
|
||||
canLoadMoreHistory: true,
|
||||
onLoadMoreHistory,
|
||||
},
|
||||
);
|
||||
|
||||
expect(scrollNode.scrollTop).toBe(400);
|
||||
});
|
||||
});
|
||||
|
||||
function renderChatArea(
|
||||
root: Root,
|
||||
messages: readonly UiMessage[],
|
||||
initialScrollReady: boolean,
|
||||
historyOptions: {
|
||||
canLoadMoreHistory?: boolean;
|
||||
isLoadingMoreHistory?: boolean;
|
||||
onLoadMoreHistory?: () => void;
|
||||
} = {},
|
||||
): void {
|
||||
act(() => {
|
||||
root.render(
|
||||
@@ -157,11 +192,32 @@ function renderChatArea(
|
||||
messages={messages}
|
||||
isReplyingAI={false}
|
||||
initialScrollReady={initialScrollReady}
|
||||
{...historyOptions}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function pull(target: HTMLElement, distance: number): void {
|
||||
act(() => {
|
||||
target.dispatchEvent(createTouchEvent("touchstart", 0));
|
||||
target.dispatchEvent(createTouchEvent("touchmove", distance));
|
||||
target.dispatchEvent(createTouchEvent("touchend", distance, true));
|
||||
});
|
||||
}
|
||||
|
||||
function createTouchEvent(
|
||||
type: string,
|
||||
clientY: number,
|
||||
ended = false,
|
||||
): Event {
|
||||
const event = new Event(type, { bubbles: true, cancelable: true });
|
||||
Object.defineProperty(event, "touches", {
|
||||
value: ended ? [] : [{ identifier: 1, clientY }],
|
||||
});
|
||||
return event;
|
||||
}
|
||||
|
||||
function createMessage(id: string): UiMessage {
|
||||
return {
|
||||
id,
|
||||
|
||||
Reference in New Issue
Block a user