Tooltip Management

Hello DataGrok Team,

As per our discussion, we would appreciate if you could expose the full tooltip/menu controls.

Also, it would be nice to have a modal (permanent) tooltip option - meaning a tooltip that doesn’t close when the mouse moves, and it’s possible to click on something inside the tooltip itself. Ideally, the same tooltip could be opened in both modes (e.g. on mouse over it shows and hides when the mouse moves, but on click it opens and stays open).

The most intuitive way for interacting with modal tooltips (in my opinion) is this:it should have an X in the upper right corner to close it, and a header area by which it can be dragged around the page. Ideally it should also close on escape key press. Other keys should not close it, because the tooltip may contain a text input. Optionally it can close on click anywhere outside the tooltip.

Thanks for your help and let me know if you have any questions.

Cheers,
Andrey

Hi Andrey,

While we might not have exposed all the internals yet, I wanted to provide an update on the progress. Some of the tooltip internals are now exposed in the Tooltip class, accessible via ui.tooltip. Here it is:

/** Represents a tooltip. */
export class Tooltip {

    /** Hides the tooltip. */
    hide() { grok_Tooltip_Hide(); }

    /** Associated the specified visual element with the corresponding item. */
    bind(element, tooltip) { grok_Tooltip_SetOn(element, tooltip); return element; }

    /** Shows the tooltip at the specified position
     * @param {HTMLElement | string} content
     * @param {number} x
     * @param {number} y */
    show(content, x, y) { grok_Tooltip_Show(content, x, y); }

    /** Returns a tooltip element.
     * @returns {HTMLElement} */
    get root() { return grok_Tooltip_Get_Root(); }

    /** @returns {isVisible} */
    get isVisible() { return grok_Tooltip_Is_Visible(); }

    /** @returns {Observable} */ get onTooltipRequest () { return __obs('d4-tooltip-request'); }
    /** @returns {Observable} */ get onTooltipShown () { return __obs('d4-tooltip-shown'); }
    /** @returns {Observable} */ get onTooltipClosed () { return __obs('d4-tooltip-closed'); }
}

Here are the samples:

Regarding the menu, we have exposed a number of methods for manipulating its items (adding/removing/clearing), here is how the class looks now:

/**
 * Menu (either top menu or popup menu).
 * Top menu sample: {@link https://public.datagrok.ai/js/samples/ui/menu}
 * Popup menu sample: {@link https://public.datagrok.ai/js/samples/ui/popup-menu}
 *
 * @example
 * DG.Menu.popup()
 *   .item('Show info', () => grok.shell.info('Info'))
 *   .separator()
 *   .items(['First', 'Second'], showBalloon)
 *   .show();
 * */
export class Menu {

    constructor(d) { this.d  = d; }

    static create() { return toJs(grok_Menu()); }

    /** Creates a popup menu.
     * @returns {Menu} */
    static popup() { return toJs(grok_Menu_Context()); }

    /** Finds a child menu item with the specified text.
     * @param {string} text
     * @returns {Menu} */
    find(text) { return toJs(grok_Menu_Find(this.d, text)); }

    /** Removes a child menu item with the specified text.
     * @param {string} text */
    remove(text) { grok_Menu_Remove(this.d, text); }

    /** Removes all child menu items. */
    clear() { grok_Menu_Clear(this.d); }

    /** Adds a menu group with the specified text.
     * @param {string} text
     * @returns {Menu} */
    group(text) { return toJs(grok_Menu_Group(this.d, text)); }

    /** Adds a menu group with the specified text and handler.
     * @param {string} text
     * @param {Function} onClick - callback with no parameters
     * @returns {Menu} */
    item(text, onClick) { return toJs(grok_Menu_Item(this.d, text, onClick)); }

    /** For each item in items, adds a menu group with the specified text and handler.
     * Returns this.
     * @param {string[]} items
     * @param {Function} onClick - a callback with one parameter
     * @returns {Menu} */
    items(items, onClick) { return toJs(grok_Menu_Items(this.d, items, onClick)); }

    /** Adds a separator line.
     *  @returns {Menu} */
    separator() { return toJs(grok_Menu_Separator(this.d)); }

    /** Shows the menu.
     * @returns {Menu} */
    show() { return toJs(grok_Menu_Show(this.d)); }
}

To intercept the popup menu, use grok.events.onContextMenu and grok.events.onContextMenuClosed events. Here is an example of the usage:

Best,
Andrew