Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/browser/ui/list/list.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 { IDragAndDropData } from '../../dnd.js';
7
import { IKeyboardEvent } from '../../keyboardEvent.js';
8
import { IMouseEvent } from '../../mouseEvent.js';
9
import { GestureEvent } from '../../touch.js';
10
import { ListViewTargetSector } from './listView.js';
11
import { IDisposable } from '../../../common/lifecycle.js';
12
13
export interface IListVirtualDelegate<T> {
14
getHeight(element: T): number;
15
getTemplateId(element: T): string;
16
hasDynamicHeight?(element: T): boolean;
17
getDynamicHeight?(element: T): number | null;
18
setDynamicHeight?(element: T, height: number): void;
19
}
20
21
export interface IListElementRenderDetails {
22
readonly height?: number;
23
readonly onScroll?: boolean;
24
}
25
26
export interface IListRenderer<T, TTemplateData> {
27
readonly templateId: string;
28
renderTemplate(container: HTMLElement): TTemplateData;
29
renderElement(element: T, index: number, templateData: TTemplateData, details?: IListElementRenderDetails): void;
30
disposeElement?(element: T, index: number, templateData: TTemplateData, details?: IListElementRenderDetails): void;
31
disposeTemplate(templateData: TTemplateData): void;
32
}
33
34
export interface IListEvent<T> {
35
readonly elements: readonly T[];
36
readonly indexes: readonly number[];
37
readonly browserEvent?: UIEvent;
38
}
39
40
export interface IListBrowserMouseEvent extends MouseEvent {
41
isHandledByList?: boolean;
42
}
43
44
export interface IListMouseEvent<T> {
45
readonly browserEvent: IListBrowserMouseEvent;
46
readonly element: T | undefined;
47
readonly index: number | undefined;
48
}
49
50
export interface IListTouchEvent<T> {
51
readonly browserEvent: TouchEvent;
52
readonly element: T | undefined;
53
readonly index: number | undefined;
54
}
55
56
export interface IListGestureEvent<T> {
57
readonly browserEvent: GestureEvent;
58
readonly element: T | undefined;
59
readonly index: number | undefined;
60
}
61
62
export interface IListDragEvent<T> {
63
readonly browserEvent: DragEvent;
64
readonly element: T | undefined;
65
readonly index: number | undefined;
66
readonly sector: ListViewTargetSector | undefined;
67
}
68
69
export interface IListContextMenuEvent<T> {
70
readonly browserEvent: UIEvent;
71
readonly element: T | undefined;
72
readonly index: number | undefined;
73
readonly anchor: HTMLElement | IMouseEvent;
74
}
75
76
export interface IIdentityProvider<T> {
77
getId(element: T): { toString(): string };
78
}
79
80
export interface IKeyboardNavigationLabelProvider<T> {
81
82
/**
83
* Return a keyboard navigation label(s) which will be used by
84
* the list for filtering/navigating. Return `undefined` to make
85
* an element always match.
86
*/
87
getKeyboardNavigationLabel(element: T): { toString(): string | undefined } | { toString(): string | undefined }[] | undefined;
88
}
89
90
export interface IKeyboardNavigationDelegate {
91
mightProducePrintableCharacter(event: IKeyboardEvent): boolean;
92
}
93
94
export const enum ListDragOverEffectType {
95
Copy,
96
Move
97
}
98
99
export const enum ListDragOverEffectPosition {
100
Over = 'drop-target',
101
Before = 'drop-target-before',
102
After = 'drop-target-after'
103
}
104
105
export interface ListDragOverEffect {
106
type: ListDragOverEffectType;
107
position?: ListDragOverEffectPosition;
108
}
109
110
export interface IListDragOverReaction {
111
accept: boolean;
112
effect?: ListDragOverEffect;
113
feedback?: number[]; // use -1 for entire list
114
}
115
116
export const ListDragOverReactions = {
117
reject(): IListDragOverReaction { return { accept: false }; },
118
accept(): IListDragOverReaction { return { accept: true }; },
119
};
120
121
/**
122
* Warning: Once passed to a list, that list takes up
123
* the responsibility of disposing it.
124
*/
125
export interface IListDragAndDrop<T> extends IDisposable {
126
getDragURI(element: T): string | null;
127
getDragLabel?(elements: T[], originalEvent: DragEvent): string | undefined;
128
onDragStart?(data: IDragAndDropData, originalEvent: DragEvent): void;
129
onDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction;
130
onDragLeave?(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void;
131
drop(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): void;
132
onDragEnd?(originalEvent: DragEvent): void;
133
}
134
135
export class ListError extends Error {
136
137
constructor(user: string, message: string) {
138
super(`ListError [${user}] ${message}`);
139
}
140
}
141
142
export abstract class CachedListVirtualDelegate<T extends object> implements IListVirtualDelegate<T> {
143
144
private cache = new WeakMap<T, number>();
145
146
getHeight(element: T): number {
147
return this.cache.get(element) ?? this.estimateHeight(element);
148
}
149
150
protected abstract estimateHeight(element: T): number;
151
abstract getTemplateId(element: T): string;
152
153
setDynamicHeight(element: T, height: number): void {
154
if (height > 0) {
155
this.cache.set(element, height);
156
}
157
}
158
}
159
160