vaadin / flow-components

Java counterpart of Vaadin Web Components
82 stars 62 forks source link

[tooltip] Add public API for setting overlayClass on the vaadin-tooltip element #4482

Open web-padawan opened 1 year ago

web-padawan commented 1 year ago

Describe your motivation

The vaadin-tooltip element instance controlled by Tooltip is marked as private:

https://github.com/vaadin/flow-components/blob/0bb105382997ac0033ec5e0359b188cc7d373e42/vaadin-flow-components-shared-parent/vaadin-flow-components-base/src/main/java/com/vaadin/flow/component/shared/Tooltip.java#L38-L41

So developers don't have an easy way to set theme on it for propagating it to the overlay.

Describe the solution you'd like

Consider adding API similar to what HasTheme interface provides to Tooltip.

Describe alternatives you've considered

Consider also using overlayClass in V24 that is added in https://github.com/vaadin/web-components/pull/5212 This might be actually a preferred solution as we now adopt native class + ::part() based styling.

Additional context

Styling individual tooltips was raised internally in this Slack thread.

jouni commented 1 year ago

I wonder what the use case for styling an individual tooltip instance would be?

web-padawan commented 1 year ago

The original thread was about a multi-line tooltip. In general, some users might want to set max-width on individual tooltips. Possibly the background, too.

TatuLund commented 1 year ago

Here is a utility JavaScript

public class TooltipUtils {

    public static void setTooltipClassName(Component comp, String className) {
        comp.getElement().executeJs(
        """
            if ($0.getElementsByTagName('vaadin-tooltip').length == 1) {
                $0.getElementsByTagName('vaadin-tooltip')[0]._overlayElement.setAttribute('class',$1);
            } else {
                const tooltips = document.getElementsByTagName('vaadin-tooltip');
                for (let i=0; i<tooltips.length; i++ ) {
                    const tooltip = tooltips[i];
                    if (tooltip._overlayElement.id === $0.getAttribute('aria-describedBy')) {
                        tooltip._overlayElement.setAttribute('class',$1)
                    }
                }
            }
         """, comp.getElement(), className);
    }
}
TatuLund commented 1 year ago

@jouni , apparently there is need https://stackoverflow.com/questions/76339066/how-to-apply-styles-for-vaadin-tooltip-overlay-only-for-certain-components

TatuLund commented 6 months ago

Due changes in Vaadin 24.2.0 the workaround presented earlier does not apply anymore. The new workaround is

public class TooltipUtils {

    public static void setTooltipClassName(Component comp, String className) {
        comp.getElement().executeJs(
        """
            if ($0.getElementsByTagName('vaadin-tooltip').length == 1) {
                $0.getElementsByTagName('vaadin-tooltip')[0]._overlayElement.setAttribute('class',$1);
            } else {
                const tooltips = document.getElementsByTagName('vaadin-tooltip');
                for (let i=0; i<tooltips.length; i++ ) {
                    const tooltip = tooltips[i];
                    if (tooltip.children[0].id === $0.getAttribute('aria-describedBy')) {
                        tooltip._overlayElement.setAttribute('class',$1)
                    }
                }
            }
         """, comp.getElement(), className);
    }
}