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:
Cats Juice
2025-07-07 15:24:26 +08:00
committed by GitHub
parent 5a81c0ab98
commit f78e0c06ac
2 changed files with 17 additions and 46 deletions

View File

@@ -17,7 +17,6 @@ import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
import { styleMap } from 'lit/directives/style-map.js';
import { throttle } from 'lodash-es';
import { HISTORY_IMAGE_ACTIONS } from '../../chat-panel/const';
import { type AIChatParams, AIProvider } from '../../provider/ai-provider';
@@ -185,8 +184,6 @@ export class AIChatContent extends SignalWatcher(
// request counter to track the latest request
private updateHistoryCounter = 0;
private wheelTriggered = false;
private lastScrollTop: number | undefined;
get messages() {
@@ -237,9 +234,6 @@ export class AIChatContent extends SignalWatcher(
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
),
});
this.wheelTriggered = false;
this.scrollToEnd();
};
private readonly updateActions = async () => {
@@ -263,9 +257,6 @@ export class AIChatContent extends SignalWatcher(
),
});
}
this.wheelTriggered = false;
this.scrollToEnd();
};
private readonly updateContext = (context: Partial<ChatContextValue>) => {
@@ -273,59 +264,31 @@ export class AIChatContent extends SignalWatcher(
this.onContextChange?.(context);
};
private readonly scrollToEnd = () => {
if (!this.wheelTriggered) {
this.chatMessagesRef.value?.scrollToEnd();
}
};
private readonly _throttledScrollToEnd = throttle(this.scrollToEnd, 600);
private readonly initChatContent = async () => {
this.isHistoryLoading = true;
await this.updateHistory();
this.isHistoryLoading = false;
};
protected override firstUpdated(): void {
protected override firstUpdated(): void {}
private _scrollListenersInitialized = false;
private _initializeScrollListeners() {
const chatMessages = this.chatMessagesRef.value;
if (chatMessages) {
chatMessages.updateComplete
.then(() => {
const scrollContainer = chatMessages.getScrollContainer();
scrollContainer?.addEventListener('wheel', () => {
this.wheelTriggered = true;
});
scrollContainer?.addEventListener('scrollend', () => {
this.lastScrollTop = scrollContainer.scrollTop;
});
this._scrollListenersInitialized = true;
})
.catch(console.error);
}
}
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
if (
changedProperties.has('host') &&
@@ -334,6 +297,10 @@ export class AIChatContent extends SignalWatcher(
) {
this.chatMessagesRef.value?.scrollToPos(this.lastScrollTop);
}
if (!this._scrollListenersInitialized) {
this._initializeScrollListeners();
}
}
public reset() {

View File

@@ -262,10 +262,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
const { isHistoryLoading } = this;
const filteredItems = this.messages;
const showDownIndicator =
this.canScrollDown &&
filteredItems.length > 0 &&
this.chatContextValue.status !== 'transmitting';
const showDownIndicator = this.canScrollDown && filteredItems.length > 0;
return html`
<div
@@ -393,6 +390,13 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
if (_changedProperties.has('isHistoryLoading')) {
this.canScrollDown = false;
}
if (
_changedProperties.has('chatContextValue') &&
this.chatContextValue.status === 'transmitting'
) {
this._onScroll();
}
}
scrollToEnd() {