Path: blob/main/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { $ } from '../../../../../base/browser/dom.js';6import { ButtonWithIcon } from '../../../../../base/browser/ui/button/button.js';7import { Codicon } from '../../../../../base/common/codicons.js';8import { Emitter } from '../../../../../base/common/event.js';9import { IMarkdownString } from '../../../../../base/common/htmlContent.js';10import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js';11import { autorun, IObservable, observableValue } from '../../../../../base/common/observable.js';12import { localize } from '../../../../../nls.js';13import { IChatRendererContent } from '../../common/chatViewModel.js';14import { ChatTreeItem } from '../chat.js';15import { IChatContentPart, IChatContentPartRenderContext } from './chatContentParts.js';161718export abstract class ChatCollapsibleContentPart extends Disposable implements IChatContentPart {1920private _domNode?: HTMLElement;2122protected readonly _onDidChangeHeight = this._register(new Emitter<void>());23public readonly onDidChangeHeight = this._onDidChangeHeight.event;2425protected readonly hasFollowingContent: boolean;26protected _isExpanded = observableValue<boolean>(this, false);27protected _collapseButton: ButtonWithIcon | undefined;2829constructor(30private title: IMarkdownString | string,31protected readonly context: IChatContentPartRenderContext,32) {33super();34this.hasFollowingContent = this.context.contentIndex + 1 < this.context.content.length;35}3637get domNode(): HTMLElement {38this._domNode ??= this.init();39return this._domNode;40}4142protected init(): HTMLElement {43const referencesLabel = this.title;444546const buttonElement = $('.chat-used-context-label', undefined);4748const collapseButton = this._register(new ButtonWithIcon(buttonElement, {49buttonBackground: undefined,50buttonBorder: undefined,51buttonForeground: undefined,52buttonHoverBackground: undefined,53buttonSecondaryBackground: undefined,54buttonSecondaryForeground: undefined,55buttonSecondaryHoverBackground: undefined,56buttonSeparator: undefined57}));58this._collapseButton = collapseButton;59this._domNode = $('.chat-used-context', undefined, buttonElement);60collapseButton.label = referencesLabel;6162this._register(collapseButton.onDidClick(() => {63const value = this._isExpanded.get();64this._isExpanded.set(!value, undefined);65}));6667this._register(autorun(r => {68const value = this._isExpanded.read(r);69collapseButton.icon = value ? Codicon.chevronDown : Codicon.chevronRight;70this._domNode?.classList.toggle('chat-used-context-collapsed', !value);71this.updateAriaLabel(collapseButton.element, typeof referencesLabel === 'string' ? referencesLabel : referencesLabel.value, this.isExpanded());7273if (this._domNode?.isConnected) {74queueMicrotask(() => {75this._onDidChangeHeight.fire();76});77}78}));7980const content = this.initContent();81this._domNode.appendChild(content);82return this._domNode;83}8485protected abstract initContent(): HTMLElement;8687abstract hasSameContent(other: IChatRendererContent, followingContent: IChatRendererContent[], element: ChatTreeItem): boolean;8889private updateAriaLabel(element: HTMLElement, label: string, expanded?: boolean): void {90element.ariaLabel = expanded ? localize('usedReferencesExpanded', "{0}, expanded", label) : localize('usedReferencesCollapsed', "{0}, collapsed", label);91}9293addDisposable(disposable: IDisposable): void {94this._register(disposable);95}9697get expanded(): IObservable<boolean> {98return this._isExpanded;99}100101protected isExpanded(): boolean {102return this._isExpanded.get();103}104105protected setExpanded(value: boolean): void {106this._isExpanded.set(value, undefined);107}108109protected setTitle(title: string): void {110this.title = title;111if (this._collapseButton) {112this._collapseButton.label = title;113this.updateAriaLabel(this._collapseButton.element, title, this.isExpanded());114}115}116}117118119