/*---------------------------------------------------------------------------------------------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 const enum HoverStyle {151/**152* The hover is anchored below the element with a pointer above it pointing at the target.153*/154Pointer = 1,155/**156* The hover is anchored to the bottom right of the cursor's location.157*/158Mouse = 2,159}160161export interface IHoverOptions {162/**163* The content to display in the primary section of the hover. The type of text determines the164* default `hideOnHover` behavior.165*/166content: IMarkdownString | string | HTMLElement;167168/**169* The target for the hover. This determines the position of the hover and it will only be170* hidden when the mouse leaves both the hover and the target. A HTMLElement can be used for171* simple cases and a IHoverTarget for more complex cases where multiple elements and/or a172* dispose method is required.173*/174target: IHoverTarget | HTMLElement;175176/*177* The container to pass to {@link IContextViewProvider.showContextView} which renders the hover178* in. This is particularly useful for more natural tab focusing behavior, where the hover is179* created as the next tab index after the element being hovered and/or to workaround the180* element's container hiding on `focusout`.181*/182container?: HTMLElement;183184/**185* An ID to associate with the hover to be used as an equality check. Normally when calling186* {@link IHoverService.showHover} the options object itself is used to determine if the hover187* is the same one that is already showing, when this is set, the ID will be used instead.188*189* When `undefined`, this will default to a serialized version of {@link content}. In this case190* it will remain `undefined` if {@link content} is a `HTMLElement`.191*/192id?: string;193194/**195* A set of actions for the hover's "status bar".196*/197actions?: IHoverAction[];198199/**200* An optional array of classes to add to the hover element.201*/202additionalClasses?: string[];203204/**205* An optional link handler for markdown links, if this is not provided the IOpenerService will206* be used to open the links using its default options.207*/208linkHandler?(url: string): void;209210/**211* Whether to trap focus in the following ways:212* - When the hover closes, focus goes to the element that had focus before the hover opened213* - If there are elements in the hover to focus, focus stays inside of the hover when tabbing214* Note that this is overridden to true when in screen reader optimized mode.215*/216trapFocus?: boolean;217218/**219* The style of the hover, this sets default values of {@link position} and {@link appearance}:220*/221style?: HoverStyle;222223/**224* Options that defines where the hover is positioned.225*/226position?: IHoverPositionOptions;227228/**229* Options that defines how long the hover is shown and when it hides.230*/231persistence?: IHoverPersistenceOptions;232233/**234* Options that define how the hover looks.235*/236appearance?: IHoverAppearanceOptions;237238/**239* An optional callback that is called when the hover is shown. This is called240* later for delayed hovers.241*/242onDidShow?(): void;243}244245// `target` is ignored for delayed hover methods as it's included in the method and added246// automatically when the hover options get resolved.247export type IDelayedHoverOptions = Omit<IHoverOptions, 'target'>;248249// `position` is ignored for delayed at mouse hover methods as it's overwritten by the mouse event.250// `showPointer` is always false when using mouse positioning251export type IDelayedHoverAtMouseOptions = Omit<IDelayedHoverOptions, 'position' | 'appearance'> & { appearance?: Omit<IHoverAppearanceOptions, 'showPointer'> };252253export interface IHoverLifecycleOptions {254/**255* The group ID of the hover. If the group ID is the same as the currently shown hover, the256* hover will be shown immediately, skipping the delay.257*258* @example Use a UUID to set a unique `groupId` for related hovers259*260* ```typescript261* const groupId = generateUuid();262* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId });263* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId });264* ```265*266* @example Use a feature-specific string to set a unqiue `groupId` for related hovers267*268* ```typescript269* showDelayedHover({ content: 'Button 1', target: someElement1 }, { groupId: 'my-feature-items' });270* showDelayedHover({ content: 'Button 2', target: someElement2 }, { groupId: 'my-feature-items' });271* ```272*/273groupId?: string;274275/**276* Whether to use a reduced delay before showing the hover. If true, the277* `workbench.hover.reducedDelay` setting is used instead of `workbench.hover.delay`.278*/279reducedDelay?: boolean;280281/**282* Whether to set up space and enter keyboard events for the hover, when these are pressed when283* the hover's target is focused it will show and focus the hover.284*285* Typically this should _not_ be used when the space or enter events are already handled by286* something else.287*/288setupKeyboardEvents?: boolean;289}290291export interface IHoverPositionOptions {292/**293* Position of the hover. The default is to show above the target. This option will be ignored294* if there is not enough room to layout the hover in the specified position, unless the295* forcePosition option is set.296*/297hoverPosition?: HoverPosition | MouseEvent;298299/**300* Force the hover position, reducing the size of the hover instead of adjusting the hover301* position.302*/303forcePosition?: boolean;304}305306export interface IHoverPersistenceOptions {307/**308* Whether to hide the hover when the mouse leaves the `target` and enters the actual hover.309* This is false by default when text is an `IMarkdownString` and true when `text` is a310* `string`. Note that this will be ignored if any `actions` are provided as hovering is311* required to make them accessible.312*313* In general hiding on hover is desired for:314* - Regular text where selection is not important315* - Markdown that contains no links where selection is not important316*/317hideOnHover?: boolean;318319/**320* Whether to hide the hover when a key is pressed.321*/322hideOnKeyDown?: boolean;323324/**325* Whether to make the hover sticky, this means it will not be hidden when the mouse leaves the326* hover.327*/328sticky?: boolean;329}330331export interface IHoverAppearanceOptions {332/**333* Whether to show the hover pointer, a little arrow that connects the target and the hover.334*/335showPointer?: boolean;336337/**338* Whether to show a compact hover, reducing the font size and padding of the hover.339*/340compact?: boolean;341342/**343* When {@link hideOnHover} is explicitly true or undefined and its auto value is detected to344* hide, show a hint at the bottom of the hover explaining how to mouse over the widget. This345* should be used in the cases where despite the hover having no interactive content, it's346* likely the user may want to interact with it somehow.347*/348showHoverHint?: boolean;349350/**351* Whether to skip the fade in animation, this should be used when hovering from one hover to352* another in the same group so it looks like the hover is moving from one element to the other.353*/354skipFadeInAnimation?: boolean;355356/**357* The max height of the hover relative to the window height.358* Accepted values: (0,1]359* Default: 0.5360*/361maxHeightRatio?: number;362}363364export interface IHoverAction {365/**366* The label to use in the hover's status bar.367*/368label: string;369370/**371* The command ID of the action, this is used to resolve the keybinding to display after the372* action label.373*/374commandId: string;375376/**377* An optional class of an icon that will be displayed before the label.378*/379iconClass?: string;380381/**382* The callback to run the action.383* @param target The action element that was activated.384*/385run(target: HTMLElement): void;386}387388/**389* A target for a hover.390*/391export interface IHoverTarget extends Partial<IDisposable> {392/**393* A set of target elements used to position the hover. If multiple elements are used the hover394* will try to not overlap any target element. An example use case for this is show a hover for395* wrapped text.396*/397readonly targetElements: readonly HTMLElement[];398399/**400* An optional absolute x coordinate to position the hover with, for example to position the401* hover using `MouseEvent.pageX`.402*/403readonly x?: number;404405/**406* An optional absolute y coordinate to position the hover with, for example to position the407* hover using `MouseEvent.pageY`.408*/409readonly y?: number;410}411412// #region Managed hover413414export interface IManagedHoverTooltipMarkdownString {415markdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);416markdownNotSupportedFallback: string | undefined;417}418419export function isManagedHoverTooltipMarkdownString(obj: unknown): obj is IManagedHoverTooltipMarkdownString {420const candidate = obj as IManagedHoverTooltipMarkdownString;421return typeof candidate === 'object' && 'markdown' in candidate && 'markdownNotSupportedFallback' in candidate;422}423424export interface IManagedHoverTooltipHTMLElement {425element: (token: CancellationToken) => HTMLElement | Promise<HTMLElement>;426}427428export function isManagedHoverTooltipHTMLElement(obj: unknown): obj is IManagedHoverTooltipHTMLElement {429const candidate = obj as IManagedHoverTooltipHTMLElement;430return typeof candidate === 'object' && 'element' in candidate;431}432433export type IManagedHoverContent = string | IManagedHoverTooltipMarkdownString | IManagedHoverTooltipHTMLElement | HTMLElement | undefined;434export type IManagedHoverContentOrFactory = IManagedHoverContent | (() => IManagedHoverContent);435436export interface IManagedHoverOptions extends Pick<IHoverOptions, 'actions' | 'linkHandler' | 'trapFocus'> {437appearance?: Pick<IHoverAppearanceOptions, 'showHoverHint'>;438}439440export interface IManagedHover extends IDisposable {441/**442* Allows to programmatically open the hover.443*/444show(focus?: boolean): void;445446/**447* Allows to programmatically hide the hover.448*/449hide(): void;450451/**452* Updates the contents of the hover.453*/454update(tooltip: IManagedHoverContent, options?: IManagedHoverOptions): void;455}456457// #endregion Managed hover458459460