fix(core): ai chat scrolldown indicator (#13382)
Close [AI-401](https://linear.app/affine-design/issue/AI-401) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved scrolling behavior in the AI chat messages panel by making the entire panel the scroll container, resulting in more consistent scroll handling. * Adjusted the position of the down-indicator for better visibility during scrolling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -314,9 +314,8 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
if (chatMessages) {
|
if (chatMessages) {
|
||||||
chatMessages.updateComplete
|
chatMessages.updateComplete
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const scrollContainer = chatMessages.getScrollContainer();
|
chatMessages.addEventListener('scrollend', () => {
|
||||||
scrollContainer?.addEventListener('scrollend', () => {
|
this.lastScrollTop = chatMessages.scrollTop;
|
||||||
this.lastScrollTop = scrollContainer.scrollTop;
|
|
||||||
});
|
});
|
||||||
this._scrollListenersInitialized = true;
|
this._scrollListenersInitialized = true;
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type { BaseSelection, ExtensionType } from '@blocksuite/affine/store';
|
|||||||
import { ArrowDownBigIcon as ArrowDownIcon } from '@blocksuite/icons/lit';
|
import { ArrowDownBigIcon as ArrowDownIcon } from '@blocksuite/icons/lit';
|
||||||
import type { Signal } from '@preact/signals-core';
|
import type { Signal } from '@preact/signals-core';
|
||||||
import { css, html, nothing, type PropertyValues } from 'lit';
|
import { css, html, nothing, type PropertyValues } from 'lit';
|
||||||
import { property, query, state } from 'lit/decorators.js';
|
import { property, state } from 'lit/decorators.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
@@ -125,10 +125,10 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.down-indicator {
|
.down-indicator {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
bottom: 24px;
|
bottom: 166px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@@ -217,9 +217,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
@query('.chat-panel-messages-container')
|
|
||||||
accessor messagesContainer: HTMLDivElement | null = null;
|
|
||||||
|
|
||||||
@property({
|
@property({
|
||||||
type: String,
|
type: String,
|
||||||
attribute: 'data-testid',
|
attribute: 'data-testid',
|
||||||
@@ -227,10 +224,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
})
|
})
|
||||||
accessor testId = 'chat-panel-messages';
|
accessor testId = 'chat-panel-messages';
|
||||||
|
|
||||||
getScrollContainer(): HTMLDivElement | null {
|
|
||||||
return this.messagesContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get _isNetworkActive() {
|
private get _isNetworkActive() {
|
||||||
return (
|
return (
|
||||||
!!this.networkSearchConfig.visible.value &&
|
!!this.networkSearchConfig.visible.value &&
|
||||||
@@ -264,8 +257,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly _onScroll = () => {
|
private readonly _onScroll = () => {
|
||||||
if (!this.messagesContainer) return;
|
const { clientHeight, scrollTop, scrollHeight } = this;
|
||||||
const { clientHeight, scrollTop, scrollHeight } = this.messagesContainer;
|
|
||||||
this.canScrollDown = scrollHeight - scrollTop - clientHeight > 200;
|
this.canScrollDown = scrollHeight - scrollTop - clientHeight > 200;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,7 +285,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
'independent-mode': !!this.independentMode,
|
'independent-mode': !!this.independentMode,
|
||||||
})}
|
})}
|
||||||
data-testid="chat-panel-messages-container"
|
data-testid="chat-panel-messages-container"
|
||||||
@scroll=${() => this._debouncedOnScroll()}
|
|
||||||
>
|
>
|
||||||
${filteredItems.length === 0
|
${filteredItems.length === 0
|
||||||
? html`<div
|
? html`<div
|
||||||
@@ -411,6 +402,12 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add scroll event listener to the host element
|
||||||
|
this.addEventListener('scroll', this._debouncedOnScroll);
|
||||||
|
disposables.add(() => {
|
||||||
|
this.removeEventListener('scroll', this._debouncedOnScroll);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override updated(_changedProperties: PropertyValues) {
|
protected override updated(_changedProperties: PropertyValues) {
|
||||||
@@ -428,9 +425,8 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
scrollToEnd() {
|
scrollToEnd() {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (!this.messagesContainer) return;
|
this.scrollTo({
|
||||||
this.messagesContainer.scrollTo({
|
top: this.scrollHeight,
|
||||||
top: this.messagesContainer.scrollHeight,
|
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -438,8 +434,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
scrollToPos(top: number) {
|
scrollToPos(top: number) {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (!this.messagesContainer) return;
|
this.scrollTo({ top });
|
||||||
this.messagesContainer.scrollTo({ top });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user