Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/browser/ui/hover/hover.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 type { IHoverDelegate } from './hoverDelegate.js';
7
import type { HoverPosition } from './hoverWidget.js';
8
import type { CancellationToken } from '../../../common/cancellation.js';
9
import type { IMarkdownString } from '../../../common/htmlContent.js';
10
import type { IDisposable } from '../../../common/lifecycle.js';
11
12
/**
13
* Enables the convenient display of rich markdown-based hovers in the workbench.
14
*/
15
export interface IHoverDelegate2 {
16
/**
17
* Shows a hover after a delay, or immediately if the {@link groupId} matches the currently
18
* shown hover.
19
*
20
* Use this method when you want to:
21
*
22
* - Control showing the hover yourself.
23
* - Show the hover after the standard delay.
24
*
25
* @param options The options of the hover.
26
* @param groupId The group ID of the hover. If the group ID is the same as the currently shown
27
* hover, the hover will be shown immediately, skipping the delay.
28
*/
29
showDelayedHover(
30
options: IHoverOptions,
31
lifecycleOptions: Pick<IHoverLifecycleOptions, 'groupId'>,
32
): IHoverWidget | undefined;
33
34
/**
35
* A simple wrapper around showDelayedHover that includes listening to events on the
36
* {@link target} element that shows the hover.
37
*
38
* Use this method when you want to:
39
*
40
* - Let the hover service handle showing the hover.
41
* - Show the hover after the standard delay.
42
* - Want the hover positioned beside the {@link target} element.
43
*
44
* @param target The target element to listener for mouseover events on.
45
* @param hoverOptions The options of the hover.
46
* @param lifecycleOptions The options of the hover's lifecycle.
47
*/
48
setupDelayedHover(
49
target: HTMLElement,
50
hoverOptions: (() => IDelayedHoverOptions) | IDelayedHoverOptions,
51
lifecycleOptions?: IHoverLifecycleOptions,
52
): IDisposable;
53
54
/**
55
* A simple wrapper around showDelayedHover that includes listening to events on the
56
* {@link target} element that shows the hover. This differs from {@link setupDelayedHover} in
57
* that the hover will be shown at the mouse position instead of the
58
* {@link target target} element's position, ignoring any
59
* {@link IHoverOptions.position position options} that are passed in.
60
*
61
* Use this method when you want to:
62
*
63
* - Let the hover service handle showing the hover.
64
* - Show the hover after the standard delay.
65
* - Want the hover positioned beside the mouse.
66
*
67
* @param target The target element to listener for mouseover events on.
68
* @param hoverOptions The options of the hover.
69
* @param lifecycleOptions The options of the hover's lifecycle.
70
*/
71
setupDelayedHoverAtMouse(
72
target: HTMLElement,
73
hoverOptions: (() => IDelayedHoverAtMouseOptions) | IDelayedHoverAtMouseOptions,
74
lifecycleOptions?: IHoverLifecycleOptions,
75
): IDisposable;
76
77
/**
78
* Shows a hover immediately, provided a hover with the same {@link options} object is not
79
* already visible.
80
*
81
* Use this method when you want to:
82
*
83
* - Control showing the hover yourself.
84
* - Show the hover immediately.
85
*
86
* @param options A set of options defining the characteristics of the hover.
87
* @param focus Whether to focus the hover (useful for keyboard accessibility).
88
*
89
* @example A simple usage with a single element target.
90
*
91
* ```typescript
92
* showInstantHover({
93
* text: new MarkdownString('Hello world'),
94
* target: someElement
95
* });
96
* ```
97
*/
98
showInstantHover(
99
options: IHoverOptions,
100
focus?: boolean
101
): IHoverWidget | undefined;
102
103
/**
104
* Hides the hover if it was visible. This call will be ignored if the hover is currently
105
* "locked" via the alt/option key unless `force` is set.
106
*/
107
hideHover(force?: boolean): void;
108
109
/**
110
* This should only be used until we have the ability to show multiple context views
111
* simultaneously. #188822
112
*/
113
showAndFocusLastHover(): void;
114
115
/**
116
* Sets up a managed hover for the given element. A managed hover will set up listeners for
117
* mouse events, show the hover after a delay and provide hooks to easily update the content.
118
*
119
* This should be used over {@link showInstantHover} when fine-grained control is not needed. The
120
* managed hover also does not scale well, consider using {@link showInstantHover} when showing hovers
121
* for many elements.
122
*
123
* @param hoverDelegate The hover delegate containing hooks and configuration for the hover.
124
* @param targetElement The target element to show the hover for.
125
* @param content The content of the hover or a factory that creates it at the time it's shown.
126
* @param options Additional options for the managed hover.
127
*
128
* @deprecated Use {@link setupDelayedHover} or {@link setupDelayedHoverAtMouse} instead where
129
* possible.
130
*/
131
setupManagedHover(hoverDelegate: IHoverDelegate, targetElement: HTMLElement, content: IManagedHoverContentOrFactory, options?: IManagedHoverOptions): IManagedHover;
132
133
/**
134
* Shows the hover for the given element if one has been setup.
135
*
136
* @param targetElement The target element of the hover, as set up in {@link setupManagedHover}.
137
*
138
* @deprecated Use {@link setupDelayedHover} or {@link setupDelayedHoverAtMouse} instead where
139
* possible.
140
*/
141
showManagedHover(targetElement: HTMLElement): void;
142
}
143
144
export interface IHoverWidget extends IDisposable {
145
/**
146
* Whether the hover widget has been disposed.
147
*/
148
readonly isDisposed: boolean;
149
}
150
151
export interface IHoverOptions {
152
/**
153
* The content to display in the primary section of the hover. The type of text determines the
154
* default `hideOnHover` behavior.
155
*/
156
content: IMarkdownString | string | HTMLElement;
157
158
/**
159
* The target for the hover. This determines the position of the hover and it will only be
160
* hidden when the mouse leaves both the hover and the target. A HTMLElement can be used for
161
* simple cases and a IHoverTarget for more complex cases where multiple elements and/or a
162
* dispose method is required.
163
*/
164
target: IHoverTarget | HTMLElement;
165
166
/*
167
* The container to pass to {@link IContextViewProvider.showContextView} which renders the hover
168
* in. This is particularly useful for more natural tab focusing behavior, where the hover is
169
* created as the next tab index after the element being hovered and/or to workaround the
170
* element's container hiding on `focusout`.
171
*/
172
container?: HTMLElement;
173
174
/**
175
* An ID to associate with the hover to be used as an equality check. Normally when calling
176
* {@link IHoverService.showHover} the options object itself is used to determine if the hover
177
* is the same one that is already showing, when this is set, the ID will be used instead.
178
*
179
* When `undefined`, this will default to a serialized version of {@link content}. In this case
180
* it will remain `undefined` if {@link content} is a `HTMLElement`.
181
*/
182
id?: string;
183
184
/**
185
* A set of actions for the hover's "status bar".
186
*/
187
actions?: IHoverAction[];
188
189
/**
190
* An optional array of classes to add to the hover element.
191
*/
192
additionalClasses?: string[];
193
194
/**
195
* An optional link handler for markdown links, if this is not provided the IOpenerService will
196
* be used to open the links using its default options.
197
*/
198
linkHandler?(url: string): void;
199
200
/**
201
* Whether to trap focus in the following ways:
202
* - When the hover closes, focus goes to the element that had focus before the hover opened
203
* - If there are elements in the hover to focus, focus stays inside of the hover when tabbing
204
* Note that this is overridden to true when in screen reader optimized mode.
205
*/
206
trapFocus?: boolean;
207
208
/**
209
* Options that defines where the hover is positioned.
210
*/
211
position?: IHoverPositionOptions;
212
213
/**
214
* Options that defines how long the hover is shown and when it hides.
215
*/
216
persistence?: IHoverPersistenceOptions;
217
218
/**
219
* Options that define how the hover looks.
220
*/
221
appearance?: IHoverAppearanceOptions;
222
}
223
224
// `target` is ignored for delayed hover methods as it's included in the method and added
225
// automatically when the hover options get resolved.
226
export type IDelayedHoverOptions = Omit<IHoverOptions, 'target'>;
227
228
// `position` is ignored for delayed at mouse hover methods as it's overwritten by the mouse event.
229
// `showPointer` is always false when using mouse positioning
230
export type IDelayedHoverAtMouseOptions = Omit<IDelayedHoverOptions, 'position' | 'appearance'> & { appearance?: Omit<IHoverAppearanceOptions, 'showPointer'> };
231
232
export interface IHoverLifecycleOptions {
233
/**
234
* The group ID of the hover. If the group ID is the same as the currently shown hover, the
235
* hover will be shown immediately, skipping the delay.
236
*
237
* @example Use a UUID to set a unique `groupId` for related hovers
238
*
239
* ```typescript
240
* const groupId = generateUuid();
241
* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId });
242
* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId });
243
* ```
244
*
245
* @example Use a feature-specific string to set a unqiue `groupId` for related hovers
246
*
247
* ```typescript
248
* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId: 'my-feature-items' });
249
* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId: 'my-feature-items' });
250
* ```
251
*/
252
groupId?: string;
253
254
/**
255
* Whether to set up space and enter keyboard events for the hover, when these are pressed when
256
* the hover's target is focused it will show and focus the hover.
257
*
258
* Typically this should _not_ be used when the space or enter events are already handled by
259
* something else.
260
*/
261
setupKeyboardEvents?: boolean;
262
}
263
264
export interface IHoverPositionOptions {
265
/**
266
* Position of the hover. The default is to show above the target. This option will be ignored
267
* if there is not enough room to layout the hover in the specified position, unless the
268
* forcePosition option is set.
269
*/
270
hoverPosition?: HoverPosition | MouseEvent;
271
272
/**
273
* Force the hover position, reducing the size of the hover instead of adjusting the hover
274
* position.
275
*/
276
forcePosition?: boolean;
277
}
278
279
export interface IHoverPersistenceOptions {
280
/**
281
* Whether to hide the hover when the mouse leaves the `target` and enters the actual hover.
282
* This is false by default when text is an `IMarkdownString` and true when `text` is a
283
* `string`. Note that this will be ignored if any `actions` are provided as hovering is
284
* required to make them accessible.
285
*
286
* In general hiding on hover is desired for:
287
* - Regular text where selection is not important
288
* - Markdown that contains no links where selection is not important
289
*/
290
hideOnHover?: boolean;
291
292
/**
293
* Whether to hide the hover when a key is pressed.
294
*/
295
hideOnKeyDown?: boolean;
296
297
/**
298
* Whether to make the hover sticky, this means it will not be hidden when the mouse leaves the
299
* hover.
300
*/
301
sticky?: boolean;
302
}
303
304
export interface IHoverAppearanceOptions {
305
/**
306
* Whether to show the hover pointer, a little arrow that connects the target and the hover.
307
*/
308
showPointer?: boolean;
309
310
/**
311
* Whether to show a compact hover, reducing the font size and padding of the hover.
312
*/
313
compact?: boolean;
314
315
/**
316
* When {@link hideOnHover} is explicitly true or undefined and its auto value is detected to
317
* hide, show a hint at the bottom of the hover explaining how to mouse over the widget. This
318
* should be used in the cases where despite the hover having no interactive content, it's
319
* likely the user may want to interact with it somehow.
320
*/
321
showHoverHint?: boolean;
322
323
/**
324
* Whether to skip the fade in animation, this should be used when hovering from one hover to
325
* another in the same group so it looks like the hover is moving from one element to the other.
326
*/
327
skipFadeInAnimation?: boolean;
328
329
/**
330
* The max height of the hover relative to the window height.
331
* Accepted values: (0,1]
332
* Default: 0.5
333
*/
334
maxHeightRatio?: number;
335
}
336
337
export interface IHoverAction {
338
/**
339
* The label to use in the hover's status bar.
340
*/
341
label: string;
342
343
/**
344
* The command ID of the action, this is used to resolve the keybinding to display after the
345
* action label.
346
*/
347
commandId: string;
348
349
/**
350
* An optional class of an icon that will be displayed before the label.
351
*/
352
iconClass?: string;
353
354
/**
355
* The callback to run the action.
356
* @param target The action element that was activated.
357
*/
358
run(target: HTMLElement): void;
359
}
360
361
/**
362
* A target for a hover.
363
*/
364
export interface IHoverTarget extends Partial<IDisposable> {
365
/**
366
* A set of target elements used to position the hover. If multiple elements are used the hover
367
* will try to not overlap any target element. An example use case for this is show a hover for
368
* wrapped text.
369
*/
370
readonly targetElements: readonly HTMLElement[];
371
372
/**
373
* An optional absolute x coordinate to position the hover with, for example to position the
374
* hover using `MouseEvent.pageX`.
375
*/
376
readonly x?: number;
377
378
/**
379
* An optional absolute y coordinate to position the hover with, for example to position the
380
* hover using `MouseEvent.pageY`.
381
*/
382
readonly y?: number;
383
}
384
385
// #region Managed hover
386
387
export interface IManagedHoverTooltipMarkdownString {
388
markdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);
389
markdownNotSupportedFallback: string | undefined;
390
}
391
392
export function isManagedHoverTooltipMarkdownString(obj: unknown): obj is IManagedHoverTooltipMarkdownString {
393
const candidate = obj as IManagedHoverTooltipMarkdownString;
394
return typeof candidate === 'object' && 'markdown' in candidate && 'markdownNotSupportedFallback' in candidate;
395
}
396
397
export interface IManagedHoverTooltipHTMLElement {
398
element: (token: CancellationToken) => HTMLElement | Promise<HTMLElement>;
399
}
400
401
export function isManagedHoverTooltipHTMLElement(obj: unknown): obj is IManagedHoverTooltipHTMLElement {
402
const candidate = obj as IManagedHoverTooltipHTMLElement;
403
return typeof candidate === 'object' && 'element' in candidate;
404
}
405
406
export type IManagedHoverContent = string | IManagedHoverTooltipMarkdownString | IManagedHoverTooltipHTMLElement | HTMLElement | undefined;
407
export type IManagedHoverContentOrFactory = IManagedHoverContent | (() => IManagedHoverContent);
408
409
export interface IManagedHoverOptions extends Pick<IHoverOptions, 'actions' | 'linkHandler' | 'trapFocus'> {
410
appearance?: Pick<IHoverAppearanceOptions, 'showHoverHint'>;
411
}
412
413
export interface IManagedHover extends IDisposable {
414
/**
415
* Allows to programmatically open the hover.
416
*/
417
show(focus?: boolean): void;
418
419
/**
420
* Allows to programmatically hide the hover.
421
*/
422
hide(): void;
423
424
/**
425
* Updates the contents of the hover.
426
*/
427
update(tooltip: IManagedHoverContent, options?: IManagedHoverOptions): void;
428
}
429
430
// #endregion Managed hover
431
432