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
5243 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 const enum HoverStyle {
152
/**
153
* The hover is anchored below the element with a pointer above it pointing at the target.
154
*/
155
Pointer = 1,
156
/**
157
* The hover is anchored to the bottom right of the cursor's location.
158
*/
159
Mouse = 2,
160
}
161
162
export interface IHoverOptions {
163
/**
164
* The content to display in the primary section of the hover. The type of text determines the
165
* default `hideOnHover` behavior.
166
*/
167
content: IMarkdownString | string | HTMLElement;
168
169
/**
170
* The target for the hover. This determines the position of the hover and it will only be
171
* hidden when the mouse leaves both the hover and the target. A HTMLElement can be used for
172
* simple cases and a IHoverTarget for more complex cases where multiple elements and/or a
173
* dispose method is required.
174
*/
175
target: IHoverTarget | HTMLElement;
176
177
/*
178
* The container to pass to {@link IContextViewProvider.showContextView} which renders the hover
179
* in. This is particularly useful for more natural tab focusing behavior, where the hover is
180
* created as the next tab index after the element being hovered and/or to workaround the
181
* element's container hiding on `focusout`.
182
*/
183
container?: HTMLElement;
184
185
/**
186
* An ID to associate with the hover to be used as an equality check. Normally when calling
187
* {@link IHoverService.showHover} the options object itself is used to determine if the hover
188
* is the same one that is already showing, when this is set, the ID will be used instead.
189
*
190
* When `undefined`, this will default to a serialized version of {@link content}. In this case
191
* it will remain `undefined` if {@link content} is a `HTMLElement`.
192
*/
193
id?: string;
194
195
/**
196
* A set of actions for the hover's "status bar".
197
*/
198
actions?: IHoverAction[];
199
200
/**
201
* An optional array of classes to add to the hover element.
202
*/
203
additionalClasses?: string[];
204
205
/**
206
* An optional link handler for markdown links, if this is not provided the IOpenerService will
207
* be used to open the links using its default options.
208
*/
209
linkHandler?(url: string): void;
210
211
/**
212
* Whether to trap focus in the following ways:
213
* - When the hover closes, focus goes to the element that had focus before the hover opened
214
* - If there are elements in the hover to focus, focus stays inside of the hover when tabbing
215
* Note that this is overridden to true when in screen reader optimized mode.
216
*/
217
trapFocus?: boolean;
218
219
/**
220
* The style of the hover, this sets default values of {@link position} and {@link appearance}:
221
*/
222
style?: HoverStyle;
223
224
/**
225
* Options that defines where the hover is positioned.
226
*/
227
position?: IHoverPositionOptions;
228
229
/**
230
* Options that defines how long the hover is shown and when it hides.
231
*/
232
persistence?: IHoverPersistenceOptions;
233
234
/**
235
* Options that define how the hover looks.
236
*/
237
appearance?: IHoverAppearanceOptions;
238
239
/**
240
* An optional callback that is called when the hover is shown. This is called
241
* later for delayed hovers.
242
*/
243
onDidShow?(): void;
244
}
245
246
// `target` is ignored for delayed hover methods as it's included in the method and added
247
// automatically when the hover options get resolved.
248
export type IDelayedHoverOptions = Omit<IHoverOptions, 'target'>;
249
250
// `position` is ignored for delayed at mouse hover methods as it's overwritten by the mouse event.
251
// `showPointer` is always false when using mouse positioning
252
export type IDelayedHoverAtMouseOptions = Omit<IDelayedHoverOptions, 'position' | 'appearance'> & { appearance?: Omit<IHoverAppearanceOptions, 'showPointer'> };
253
254
export interface IHoverLifecycleOptions {
255
/**
256
* The group ID of the hover. If the group ID is the same as the currently shown hover, the
257
* hover will be shown immediately, skipping the delay.
258
*
259
* @example Use a UUID to set a unique `groupId` for related hovers
260
*
261
* ```typescript
262
* const groupId = generateUuid();
263
* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId });
264
* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId });
265
* ```
266
*
267
* @example Use a feature-specific string to set a unqiue `groupId` for related hovers
268
*
269
* ```typescript
270
* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId: 'my-feature-items' });
271
* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId: 'my-feature-items' });
272
* ```
273
*/
274
groupId?: string;
275
276
/**
277
* Whether to use a reduced delay before showing the hover. If true, the
278
* `workbench.hover.reducedDelay` setting is used instead of `workbench.hover.delay`.
279
*/
280
reducedDelay?: boolean;
281
282
/**
283
* Whether to set up space and enter keyboard events for the hover, when these are pressed when
284
* the hover's target is focused it will show and focus the hover.
285
*
286
* Typically this should _not_ be used when the space or enter events are already handled by
287
* something else.
288
*/
289
setupKeyboardEvents?: boolean;
290
}
291
292
export interface IHoverPositionOptions {
293
/**
294
* Position of the hover. The default is to show above the target. This option will be ignored
295
* if there is not enough room to layout the hover in the specified position, unless the
296
* forcePosition option is set.
297
*/
298
hoverPosition?: HoverPosition | MouseEvent;
299
300
/**
301
* Force the hover position, reducing the size of the hover instead of adjusting the hover
302
* position.
303
*/
304
forcePosition?: boolean;
305
}
306
307
export interface IHoverPersistenceOptions {
308
/**
309
* Whether to hide the hover when the mouse leaves the `target` and enters the actual hover.
310
* This is false by default when text is an `IMarkdownString` and true when `text` is a
311
* `string`. Note that this will be ignored if any `actions` are provided as hovering is
312
* required to make them accessible.
313
*
314
* In general hiding on hover is desired for:
315
* - Regular text where selection is not important
316
* - Markdown that contains no links where selection is not important
317
*/
318
hideOnHover?: boolean;
319
320
/**
321
* Whether to hide the hover when a key is pressed.
322
*/
323
hideOnKeyDown?: boolean;
324
325
/**
326
* Whether to make the hover sticky, this means it will not be hidden when the mouse leaves the
327
* hover.
328
*/
329
sticky?: boolean;
330
}
331
332
export interface IHoverAppearanceOptions {
333
/**
334
* Whether to show the hover pointer, a little arrow that connects the target and the hover.
335
*/
336
showPointer?: boolean;
337
338
/**
339
* Whether to show a compact hover, reducing the font size and padding of the hover.
340
*/
341
compact?: boolean;
342
343
/**
344
* When {@link hideOnHover} is explicitly true or undefined and its auto value is detected to
345
* hide, show a hint at the bottom of the hover explaining how to mouse over the widget. This
346
* should be used in the cases where despite the hover having no interactive content, it's
347
* likely the user may want to interact with it somehow.
348
*/
349
showHoverHint?: boolean;
350
351
/**
352
* Whether to skip the fade in animation, this should be used when hovering from one hover to
353
* another in the same group so it looks like the hover is moving from one element to the other.
354
*/
355
skipFadeInAnimation?: boolean;
356
357
/**
358
* The max height of the hover relative to the window height.
359
* Accepted values: (0,1]
360
* Default: 0.5
361
*/
362
maxHeightRatio?: number;
363
}
364
365
export interface IHoverAction {
366
/**
367
* The label to use in the hover's status bar.
368
*/
369
label: string;
370
371
/**
372
* The command ID of the action, this is used to resolve the keybinding to display after the
373
* action label.
374
*/
375
commandId: string;
376
377
/**
378
* An optional class of an icon that will be displayed before the label.
379
*/
380
iconClass?: string;
381
382
/**
383
* The callback to run the action.
384
* @param target The action element that was activated.
385
*/
386
run(target: HTMLElement): void;
387
}
388
389
/**
390
* A target for a hover.
391
*/
392
export interface IHoverTarget extends Partial<IDisposable> {
393
/**
394
* A set of target elements used to position the hover. If multiple elements are used the hover
395
* will try to not overlap any target element. An example use case for this is show a hover for
396
* wrapped text.
397
*/
398
readonly targetElements: readonly HTMLElement[];
399
400
/**
401
* An optional absolute x coordinate to position the hover with, for example to position the
402
* hover using `MouseEvent.pageX`.
403
*/
404
readonly x?: number;
405
406
/**
407
* An optional absolute y coordinate to position the hover with, for example to position the
408
* hover using `MouseEvent.pageY`.
409
*/
410
readonly y?: number;
411
}
412
413
// #region Managed hover
414
415
export interface IManagedHoverTooltipMarkdownString {
416
markdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);
417
markdownNotSupportedFallback: string | undefined;
418
}
419
420
export function isManagedHoverTooltipMarkdownString(obj: unknown): obj is IManagedHoverTooltipMarkdownString {
421
const candidate = obj as IManagedHoverTooltipMarkdownString;
422
return typeof candidate === 'object' && 'markdown' in candidate && 'markdownNotSupportedFallback' in candidate;
423
}
424
425
export interface IManagedHoverTooltipHTMLElement {
426
element: (token: CancellationToken) => HTMLElement | Promise<HTMLElement>;
427
}
428
429
export function isManagedHoverTooltipHTMLElement(obj: unknown): obj is IManagedHoverTooltipHTMLElement {
430
const candidate = obj as IManagedHoverTooltipHTMLElement;
431
return typeof candidate === 'object' && 'element' in candidate;
432
}
433
434
export type IManagedHoverContent = string | IManagedHoverTooltipMarkdownString | IManagedHoverTooltipHTMLElement | HTMLElement | undefined;
435
export type IManagedHoverContentOrFactory = IManagedHoverContent | (() => IManagedHoverContent);
436
437
export interface IManagedHoverOptions extends Pick<IHoverOptions, 'actions' | 'linkHandler' | 'trapFocus'> {
438
appearance?: Pick<IHoverAppearanceOptions, 'showHoverHint'>;
439
}
440
441
export interface IManagedHover extends IDisposable {
442
/**
443
* Allows to programmatically open the hover.
444
*/
445
show(focus?: boolean): void;
446
447
/**
448
* Allows to programmatically hide the hover.
449
*/
450
hide(): void;
451
452
/**
453
* Updates the contents of the hover.
454
*/
455
update(tooltip: IManagedHoverContent, options?: IManagedHoverOptions): void;
456
}
457
458
// #endregion Managed hover
459
460