Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { $ } from '../../../../../base/browser/dom.js';
7
import { ButtonWithIcon } from '../../../../../base/browser/ui/button/button.js';
8
import { Codicon } from '../../../../../base/common/codicons.js';
9
import { Emitter } from '../../../../../base/common/event.js';
10
import { IMarkdownString } from '../../../../../base/common/htmlContent.js';
11
import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js';
12
import { autorun, IObservable, observableValue } from '../../../../../base/common/observable.js';
13
import { localize } from '../../../../../nls.js';
14
import { IChatRendererContent } from '../../common/chatViewModel.js';
15
import { ChatTreeItem } from '../chat.js';
16
import { IChatContentPart, IChatContentPartRenderContext } from './chatContentParts.js';
17
18
19
export abstract class ChatCollapsibleContentPart extends Disposable implements IChatContentPart {
20
21
private _domNode?: HTMLElement;
22
23
protected readonly _onDidChangeHeight = this._register(new Emitter<void>());
24
public readonly onDidChangeHeight = this._onDidChangeHeight.event;
25
26
protected readonly hasFollowingContent: boolean;
27
protected _isExpanded = observableValue<boolean>(this, false);
28
protected _collapseButton: ButtonWithIcon | undefined;
29
30
constructor(
31
private title: IMarkdownString | string,
32
protected readonly context: IChatContentPartRenderContext,
33
) {
34
super();
35
this.hasFollowingContent = this.context.contentIndex + 1 < this.context.content.length;
36
}
37
38
get domNode(): HTMLElement {
39
this._domNode ??= this.init();
40
return this._domNode;
41
}
42
43
protected init(): HTMLElement {
44
const referencesLabel = this.title;
45
46
47
const buttonElement = $('.chat-used-context-label', undefined);
48
49
const collapseButton = this._register(new ButtonWithIcon(buttonElement, {
50
buttonBackground: undefined,
51
buttonBorder: undefined,
52
buttonForeground: undefined,
53
buttonHoverBackground: undefined,
54
buttonSecondaryBackground: undefined,
55
buttonSecondaryForeground: undefined,
56
buttonSecondaryHoverBackground: undefined,
57
buttonSeparator: undefined
58
}));
59
this._collapseButton = collapseButton;
60
this._domNode = $('.chat-used-context', undefined, buttonElement);
61
collapseButton.label = referencesLabel;
62
63
this._register(collapseButton.onDidClick(() => {
64
const value = this._isExpanded.get();
65
this._isExpanded.set(!value, undefined);
66
}));
67
68
this._register(autorun(r => {
69
const value = this._isExpanded.read(r);
70
collapseButton.icon = value ? Codicon.chevronDown : Codicon.chevronRight;
71
this._domNode?.classList.toggle('chat-used-context-collapsed', !value);
72
this.updateAriaLabel(collapseButton.element, typeof referencesLabel === 'string' ? referencesLabel : referencesLabel.value, this.isExpanded());
73
74
if (this._domNode?.isConnected) {
75
queueMicrotask(() => {
76
this._onDidChangeHeight.fire();
77
});
78
}
79
}));
80
81
const content = this.initContent();
82
this._domNode.appendChild(content);
83
return this._domNode;
84
}
85
86
protected abstract initContent(): HTMLElement;
87
88
abstract hasSameContent(other: IChatRendererContent, followingContent: IChatRendererContent[], element: ChatTreeItem): boolean;
89
90
private updateAriaLabel(element: HTMLElement, label: string, expanded?: boolean): void {
91
element.ariaLabel = expanded ? localize('usedReferencesExpanded', "{0}, expanded", label) : localize('usedReferencesCollapsed', "{0}, collapsed", label);
92
}
93
94
addDisposable(disposable: IDisposable): void {
95
this._register(disposable);
96
}
97
98
get expanded(): IObservable<boolean> {
99
return this._isExpanded;
100
}
101
102
protected isExpanded(): boolean {
103
return this._isExpanded.get();
104
}
105
106
protected setExpanded(value: boolean): void {
107
this._isExpanded.set(value, undefined);
108
}
109
110
protected setTitle(title: string): void {
111
this.title = title;
112
if (this._collapseButton) {
113
this._collapseButton.label = title;
114
this.updateAriaLabel(this._collapseButton.element, title, this.isExpanded());
115
}
116
}
117
}
118
119