/*---------------------------------------------------------------------------------------------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 type { IHoverDelegate } from './hoverDelegate.js';6import type { HoverPosition } from './hoverWidget.js';7import type { CancellationToken } from '../../../common/cancellation.js';8import type { IMarkdownString } from '../../../common/htmlContent.js';9import type { IDisposable } from '../../../common/lifecycle.js';1011/**12* Enables the convenient display of rich markdown-based hovers in the workbench.13*/14export interface IHoverDelegate2 {15/**16* Shows a hover after a delay, or immediately if the {@link groupId} matches the currently17* shown hover.18*19* Use this method when you want to:20*21* - Control showing the hover yourself.22* - Show the hover after the standard delay.23*24* @param options The options of the hover.25* @param groupId The group ID of the hover. If the group ID is the same as the currently shown26* hover, the hover will be shown immediately, skipping the delay.27*/28showDelayedHover(29options: IHoverOptions,30lifecycleOptions: Pick<IHoverLifecycleOptions, 'groupId'>,31): IHoverWidget | undefined;3233/**34* A simple wrapper around showDelayedHover that includes listening to events on the35* {@link target} element that shows the hover.36*37* Use this method when you want to:38*39* - Let the hover service handle showing the hover.40* - Show the hover after the standard delay.41* - Want the hover positioned beside the {@link target} element.42*43* @param target The target element to listener for mouseover events on.44* @param hoverOptions The options of the hover.45* @param lifecycleOptions The options of the hover's lifecycle.46*/47setupDelayedHover(48target: HTMLElement,49hoverOptions: (() => IDelayedHoverOptions) | IDelayedHoverOptions,50lifecycleOptions?: IHoverLifecycleOptions,51): IDisposable;5253/**54* A simple wrapper around showDelayedHover that includes listening to events on the55* {@link target} element that shows the hover. This differs from {@link setupDelayedHover} in56* that the hover will be shown at the mouse position instead of the57* {@link target target} element's position, ignoring any58* {@link IHoverOptions.position position options} that are passed in.59*60* Use this method when you want to:61*62* - Let the hover service handle showing the hover.63* - Show the hover after the standard delay.64* - Want the hover positioned beside the mouse.65*66* @param target The target element to listener for mouseover events on.67* @param hoverOptions The options of the hover.68* @param lifecycleOptions The options of the hover's lifecycle.69*/70setupDelayedHoverAtMouse(71target: HTMLElement,72hoverOptions: (() => IDelayedHoverAtMouseOptions) | IDelayedHoverAtMouseOptions,73lifecycleOptions?: IHoverLifecycleOptions,74): IDisposable;7576/**77* Shows a hover immediately, provided a hover with the same {@link options} object is not78* already visible.79*80* Use this method when you want to:81*82* - Control showing the hover yourself.83* - Show the hover immediately.84*85* @param options A set of options defining the characteristics of the hover.86* @param focus Whether to focus the hover (useful for keyboard accessibility).87*88* @example A simple usage with a single element target.89*90* ```typescript91* showInstantHover({92* text: new MarkdownString('Hello world'),93* target: someElement94* });95* ```96*/97showInstantHover(98options: IHoverOptions,99focus?: boolean100): IHoverWidget | undefined;101102/**103* Hides the hover if it was visible. This call will be ignored if the hover is currently104* "locked" via the alt/option key unless `force` is set.105*/106hideHover(force?: boolean): void;107108/**109* This should only be used until we have the ability to show multiple context views110* simultaneously. #188822111*/112showAndFocusLastHover(): void;113114/**115* Sets up a managed hover for the given element. A managed hover will set up listeners for116* mouse events, show the hover after a delay and provide hooks to easily update the content.117*118* This should be used over {@link showInstantHover} when fine-grained control is not needed. The119* managed hover also does not scale well, consider using {@link showInstantHover} when showing hovers120* for many elements.121*122* @param hoverDelegate The hover delegate containing hooks and configuration for the hover.123* @param targetElement The target element to show the hover for.124* @param content The content of the hover or a factory that creates it at the time it's shown.125* @param options Additional options for the managed hover.126*127* @deprecated Use {@link setupDelayedHover} or {@link setupDelayedHoverAtMouse} instead where128* possible.129*/130setupManagedHover(hoverDelegate: IHoverDelegate, targetElement: HTMLElement, content: IManagedHoverContentOrFactory, options?: IManagedHoverOptions): IManagedHover;131132/**133* Shows the hover for the given element if one has been setup.134*135* @param targetElement The target element of the hover, as set up in {@link setupManagedHover}.136*137* @deprecated Use {@link setupDelayedHover} or {@link setupDelayedHoverAtMouse} instead where138* possible.139*/140showManagedHover(targetElement: HTMLElement): void;141}142143export interface IHoverWidget extends IDisposable {144/**145* Whether the hover widget has been disposed.146*/147readonly isDisposed: boolean;148}149150export interface IHoverOptions {151/**152* The content to display in the primary section of the hover. The type of text determines the153* default `hideOnHover` behavior.154*/155content: IMarkdownString | string | HTMLElement;156157/**158* The target for the hover. This determines the position of the hover and it will only be159* hidden when the mouse leaves both the hover and the target. A HTMLElement can be used for160* simple cases and a IHoverTarget for more complex cases where multiple elements and/or a161* dispose method is required.162*/163target: IHoverTarget | HTMLElement;164165/*166* The container to pass to {@link IContextViewProvider.showContextView} which renders the hover167* in. This is particularly useful for more natural tab focusing behavior, where the hover is168* created as the next tab index after the element being hovered and/or to workaround the169* element's container hiding on `focusout`.170*/171container?: HTMLElement;172173/**174* An ID to associate with the hover to be used as an equality check. Normally when calling175* {@link IHoverService.showHover} the options object itself is used to determine if the hover176* is the same one that is already showing, when this is set, the ID will be used instead.177*178* When `undefined`, this will default to a serialized version of {@link content}. In this case179* it will remain `undefined` if {@link content} is a `HTMLElement`.180*/181id?: string;182183/**184* A set of actions for the hover's "status bar".185*/186actions?: IHoverAction[];187188/**189* An optional array of classes to add to the hover element.190*/191additionalClasses?: string[];192193/**194* An optional link handler for markdown links, if this is not provided the IOpenerService will195* be used to open the links using its default options.196*/197linkHandler?(url: string): void;198199/**200* Whether to trap focus in the following ways:201* - When the hover closes, focus goes to the element that had focus before the hover opened202* - If there are elements in the hover to focus, focus stays inside of the hover when tabbing203* Note that this is overridden to true when in screen reader optimized mode.204*/205trapFocus?: boolean;206207/**208* Options that defines where the hover is positioned.209*/210position?: IHoverPositionOptions;211212/**213* Options that defines how long the hover is shown and when it hides.214*/215persistence?: IHoverPersistenceOptions;216217/**218* Options that define how the hover looks.219*/220appearance?: IHoverAppearanceOptions;221}222223// `target` is ignored for delayed hover methods as it's included in the method and added224// automatically when the hover options get resolved.225export type IDelayedHoverOptions = Omit<IHoverOptions, 'target'>;226227// `position` is ignored for delayed at mouse hover methods as it's overwritten by the mouse event.228// `showPointer` is always false when using mouse positioning229export type IDelayedHoverAtMouseOptions = Omit<IDelayedHoverOptions, 'position' | 'appearance'> & { appearance?: Omit<IHoverAppearanceOptions, 'showPointer'> };230231export interface IHoverLifecycleOptions {232/**233* The group ID of the hover. If the group ID is the same as the currently shown hover, the234* hover will be shown immediately, skipping the delay.235*236* @example Use a UUID to set a unique `groupId` for related hovers237*238* ```typescript239* const groupId = generateUuid();240* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId });241* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId });242* ```243*244* @example Use a feature-specific string to set a unqiue `groupId` for related hovers245*246* ```typescript247* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId: 'my-feature-items' });248* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId: 'my-feature-items' });249* ```250*/251groupId?: string;252253/**254* Whether to set up space and enter keyboard events for the hover, when these are pressed when255* the hover's target is focused it will show and focus the hover.256*257* Typically this should _not_ be used when the space or enter events are already handled by258* something else.259*/260setupKeyboardEvents?: boolean;261}262263export interface IHoverPositionOptions {264/**265* Position of the hover. The default is to show above the target. This option will be ignored266* if there is not enough room to layout the hover in the specified position, unless the267* forcePosition option is set.268*/269hoverPosition?: HoverPosition | MouseEvent;270271/**272* Force the hover position, reducing the size of the hover instead of adjusting the hover273* position.274*/275forcePosition?: boolean;276}277278export interface IHoverPersistenceOptions {279/**280* Whether to hide the hover when the mouse leaves the `target` and enters the actual hover.281* This is false by default when text is an `IMarkdownString` and true when `text` is a282* `string`. Note that this will be ignored if any `actions` are provided as hovering is283* required to make them accessible.284*285* In general hiding on hover is desired for:286* - Regular text where selection is not important287* - Markdown that contains no links where selection is not important288*/289hideOnHover?: boolean;290291/**292* Whether to hide the hover when a key is pressed.293*/294hideOnKeyDown?: boolean;295296/**297* Whether to make the hover sticky, this means it will not be hidden when the mouse leaves the298* hover.299*/300sticky?: boolean;301}302303export interface IHoverAppearanceOptions {304/**305* Whether to show the hover pointer, a little arrow that connects the target and the hover.306*/307showPointer?: boolean;308309/**310* Whether to show a compact hover, reducing the font size and padding of the hover.311*/312compact?: boolean;313314/**315* When {@link hideOnHover} is explicitly true or undefined and its auto value is detected to316* hide, show a hint at the bottom of the hover explaining how to mouse over the widget. This317* should be used in the cases where despite the hover having no interactive content, it's318* likely the user may want to interact with it somehow.319*/320showHoverHint?: boolean;321322/**323* Whether to skip the fade in animation, this should be used when hovering from one hover to324* another in the same group so it looks like the hover is moving from one element to the other.325*/326skipFadeInAnimation?: boolean;327328/**329* The max height of the hover relative to the window height.330* Accepted values: (0,1]331* Default: 0.5332*/333maxHeightRatio?: number;334}335336export interface IHoverAction {337/**338* The label to use in the hover's status bar.339*/340label: string;341342/**343* The command ID of the action, this is used to resolve the keybinding to display after the344* action label.345*/346commandId: string;347348/**349* An optional class of an icon that will be displayed before the label.350*/351iconClass?: string;352353/**354* The callback to run the action.355* @param target The action element that was activated.356*/357run(target: HTMLElement): void;358}359360/**361* A target for a hover.362*/363export interface IHoverTarget extends Partial<IDisposable> {364/**365* A set of target elements used to position the hover. If multiple elements are used the hover366* will try to not overlap any target element. An example use case for this is show a hover for367* wrapped text.368*/369readonly targetElements: readonly HTMLElement[];370371/**372* An optional absolute x coordinate to position the hover with, for example to position the373* hover using `MouseEvent.pageX`.374*/375readonly x?: number;376377/**378* An optional absolute y coordinate to position the hover with, for example to position the379* hover using `MouseEvent.pageY`.380*/381readonly y?: number;382}383384// #region Managed hover385386export interface IManagedHoverTooltipMarkdownString {387markdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);388markdownNotSupportedFallback: string | undefined;389}390391export function isManagedHoverTooltipMarkdownString(obj: unknown): obj is IManagedHoverTooltipMarkdownString {392const candidate = obj as IManagedHoverTooltipMarkdownString;393return typeof candidate === 'object' && 'markdown' in candidate && 'markdownNotSupportedFallback' in candidate;394}395396export interface IManagedHoverTooltipHTMLElement {397element: (token: CancellationToken) => HTMLElement | Promise<HTMLElement>;398}399400export function isManagedHoverTooltipHTMLElement(obj: unknown): obj is IManagedHoverTooltipHTMLElement {401const candidate = obj as IManagedHoverTooltipHTMLElement;402return typeof candidate === 'object' && 'element' in candidate;403}404405export type IManagedHoverContent = string | IManagedHoverTooltipMarkdownString | IManagedHoverTooltipHTMLElement | HTMLElement | undefined;406export type IManagedHoverContentOrFactory = IManagedHoverContent | (() => IManagedHoverContent);407408export interface IManagedHoverOptions extends Pick<IHoverOptions, 'actions' | 'linkHandler' | 'trapFocus'> {409appearance?: Pick<IHoverAppearanceOptions, 'showHoverHint'>;410}411412export interface IManagedHover extends IDisposable {413/**414* Allows to programmatically open the hover.415*/416show(focus?: boolean): void;417418/**419* Allows to programmatically hide the hover.420*/421hide(): void;422423/**424* Updates the contents of the hover.425*/426update(tooltip: IManagedHoverContent, options?: IManagedHoverOptions): void;427}428429// #endregion Managed hover430431432