feat(core): remove auto-scroll when chatting and display down-arrow instead (#13066)
close AI-311 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Simplified chat scroll behavior by removing wheel event tracking and conditional scroll-to-end logic. * Improved scroll position tracking by only updating on scroll end events. * Streamlined scroll-down indicator logic for chat messages, making it more responsive during message transmission. * **Bug Fixes** * Ensured scroll state updates correctly when new messages are being sent. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -17,7 +17,6 @@ import { property, state } from 'lit/decorators.js';
|
|||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
import { throttle } from 'lodash-es';
|
|
||||||
|
|
||||||
import { HISTORY_IMAGE_ACTIONS } from '../../chat-panel/const';
|
import { HISTORY_IMAGE_ACTIONS } from '../../chat-panel/const';
|
||||||
import { type AIChatParams, AIProvider } from '../../provider/ai-provider';
|
import { type AIChatParams, AIProvider } from '../../provider/ai-provider';
|
||||||
@@ -185,8 +184,6 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
// request counter to track the latest request
|
// request counter to track the latest request
|
||||||
private updateHistoryCounter = 0;
|
private updateHistoryCounter = 0;
|
||||||
|
|
||||||
private wheelTriggered = false;
|
|
||||||
|
|
||||||
private lastScrollTop: number | undefined;
|
private lastScrollTop: number | undefined;
|
||||||
|
|
||||||
get messages() {
|
get messages() {
|
||||||
@@ -237,9 +234,6 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.wheelTriggered = false;
|
|
||||||
this.scrollToEnd();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly updateActions = async () => {
|
private readonly updateActions = async () => {
|
||||||
@@ -263,9 +257,6 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.wheelTriggered = false;
|
|
||||||
this.scrollToEnd();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly updateContext = (context: Partial<ChatContextValue>) => {
|
private readonly updateContext = (context: Partial<ChatContextValue>) => {
|
||||||
@@ -273,59 +264,31 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
this.onContextChange?.(context);
|
this.onContextChange?.(context);
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly scrollToEnd = () => {
|
|
||||||
if (!this.wheelTriggered) {
|
|
||||||
this.chatMessagesRef.value?.scrollToEnd();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly _throttledScrollToEnd = throttle(this.scrollToEnd, 600);
|
|
||||||
|
|
||||||
private readonly initChatContent = async () => {
|
private readonly initChatContent = async () => {
|
||||||
this.isHistoryLoading = true;
|
this.isHistoryLoading = true;
|
||||||
await this.updateHistory();
|
await this.updateHistory();
|
||||||
this.isHistoryLoading = false;
|
this.isHistoryLoading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override firstUpdated(): void {
|
protected override firstUpdated(): void {}
|
||||||
|
|
||||||
|
private _scrollListenersInitialized = false;
|
||||||
|
private _initializeScrollListeners() {
|
||||||
const chatMessages = this.chatMessagesRef.value;
|
const chatMessages = this.chatMessagesRef.value;
|
||||||
if (chatMessages) {
|
if (chatMessages) {
|
||||||
chatMessages.updateComplete
|
chatMessages.updateComplete
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const scrollContainer = chatMessages.getScrollContainer();
|
const scrollContainer = chatMessages.getScrollContainer();
|
||||||
scrollContainer?.addEventListener('wheel', () => {
|
|
||||||
this.wheelTriggered = true;
|
|
||||||
});
|
|
||||||
scrollContainer?.addEventListener('scrollend', () => {
|
scrollContainer?.addEventListener('scrollend', () => {
|
||||||
this.lastScrollTop = scrollContainer.scrollTop;
|
this.lastScrollTop = scrollContainer.scrollTop;
|
||||||
});
|
});
|
||||||
|
this._scrollListenersInitialized = true;
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override updated(changedProperties: PropertyValues) {
|
protected override updated(changedProperties: PropertyValues) {
|
||||||
if (this.chatContextValue.status === 'loading') {
|
|
||||||
// reset the wheel triggered flag when the status is loading
|
|
||||||
this.wheelTriggered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
changedProperties.has('chatContextValue') &&
|
|
||||||
(this.chatContextValue.status === 'loading' ||
|
|
||||||
this.chatContextValue.status === 'error' ||
|
|
||||||
this.chatContextValue.status === 'success')
|
|
||||||
) {
|
|
||||||
setTimeout(this.scrollToEnd, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
changedProperties.has('chatContextValue') &&
|
|
||||||
this.chatContextValue.status === 'transmitting'
|
|
||||||
) {
|
|
||||||
this._throttledScrollToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore pinned chat scroll position
|
// restore pinned chat scroll position
|
||||||
if (
|
if (
|
||||||
changedProperties.has('host') &&
|
changedProperties.has('host') &&
|
||||||
@@ -334,6 +297,10 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
) {
|
) {
|
||||||
this.chatMessagesRef.value?.scrollToPos(this.lastScrollTop);
|
this.chatMessagesRef.value?.scrollToPos(this.lastScrollTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this._scrollListenersInitialized) {
|
||||||
|
this._initializeScrollListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset() {
|
public reset() {
|
||||||
|
|||||||
@@ -262,10 +262,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
const { isHistoryLoading } = this;
|
const { isHistoryLoading } = this;
|
||||||
const filteredItems = this.messages;
|
const filteredItems = this.messages;
|
||||||
|
|
||||||
const showDownIndicator =
|
const showDownIndicator = this.canScrollDown && filteredItems.length > 0;
|
||||||
this.canScrollDown &&
|
|
||||||
filteredItems.length > 0 &&
|
|
||||||
this.chatContextValue.status !== 'transmitting';
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -393,6 +390,13 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
if (_changedProperties.has('isHistoryLoading')) {
|
if (_changedProperties.has('isHistoryLoading')) {
|
||||||
this.canScrollDown = false;
|
this.canScrollDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
_changedProperties.has('chatContextValue') &&
|
||||||
|
this.chatContextValue.status === 'transmitting'
|
||||||
|
) {
|
||||||
|
this._onScroll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollToEnd() {
|
scrollToEnd() {
|
||||||
|
|||||||
Reference in New Issue
Block a user