Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions packages/component-base/src/tooltip-controller.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ export class TooltipController extends SlotController {
*/
manual: boolean;

/**
* When true, the tooltip is opened programmatically.
* Only works if `manual` is set to `true`.
*/
opened: boolean;

/**
* Position of the tooltip with respect to its target.
*/
Expand All @@ -74,11 +68,6 @@ export class TooltipController extends SlotController {
*/
setManual(manual: boolean): void;

/**
* Toggle opened state on the slotted tooltip.
*/
setOpened(opened: boolean): void;

/**
* Set default position for the slotted tooltip.
* This can be overridden by setting the position
Expand All @@ -96,4 +85,18 @@ export class TooltipController extends SlotController {
* Set an HTML element to attach the tooltip to.
*/
setTarget(target: HTMLElement): void;

/**
* Schedule opening the slotted tooltip. Respects the tooltip's
* configured `hoverDelay` / `focusDelay` and the shared warm-up state.
* No-op when no tooltip is slotted.
*/
open(options?: { hover?: boolean; focus?: boolean; immediate?: boolean }): void;

/**
* Schedule closing the slotted tooltip. Respects the tooltip's
* configured `hideDelay` unless `immediate` is true.
* No-op when no tooltip is slotted.
*/
close(immediate?: boolean): void;
}
45 changes: 28 additions & 17 deletions packages/component-base/src/tooltip-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
tooltipNode.manual = this.manual;
}

if (this.opened !== undefined) {
tooltipNode.opened = this.opened;
}

if (this.position !== undefined) {
tooltipNode._position = this.position;
}
Expand Down Expand Up @@ -113,19 +109,6 @@
}
}

/**
* Toggle opened state on the slotted tooltip.
* @param {boolean} opened
*/
setOpened(opened) {
this.opened = opened;

const tooltipNode = this.node;
if (tooltipNode) {
tooltipNode.opened = opened;
}
}

/**
* Set default position for the slotted tooltip.
* This can be overridden by setting the position
Expand Down Expand Up @@ -168,6 +151,34 @@
}
}

/**
* Schedule opening the slotted tooltip. Respects the tooltip's
* configured `hoverDelay` / `focusDelay` and the shared warm-up state.
* No-op when no tooltip is slotted.
*
* @param {{ hover?: boolean, focus?: boolean, immediate?: boolean }} [options]
*/
open(options) {
const tooltipNode = this.node;
if (tooltipNode && tooltipNode.isConnected) {

Check warning on line 163 in packages/component-base/src/tooltip-controller.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=vaadin_web-components&issues=AZ3ARcKLqgC5XTKxzcBQ&open=AZ3ARcKLqgC5XTKxzcBQ&pullRequest=11568
tooltipNode._stateController.open(options);
}
}

/**
* Schedule closing the slotted tooltip. Respects the tooltip's
* configured `hideDelay` unless `immediate` is true.
* No-op when no tooltip is slotted.
*
* @param {boolean} [immediate]
*/
close(immediate) {
const tooltipNode = this.node;
if (tooltipNode) {
tooltipNode._stateController.close(immediate);
}
}

/** @private */
__onContentChange(event) {
this.__notifyChange(event.target);
Expand Down
47 changes: 27 additions & 20 deletions packages/component-base/test/tooltip-controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@ describe('TooltipController', () => {
expect(tooltip.manual).to.be.false;
});

it('should update tooltip opened using controller setOpened method', () => {
controller.setOpened(true);
expect(tooltip.opened).to.be.true;

controller.setOpened(false);
expect(tooltip.opened).to.be.false;
});

it('should update tooltip shouldShow using controller shouldShow method', () => {
const shouldShow = () => true;
controller.setShouldShow(shouldShow);
Expand All @@ -85,6 +77,25 @@ describe('TooltipController', () => {
controller.setAriaTarget(input);
expect(tooltip.ariaTarget).to.equal(input);
});

it('should delegate open to the tooltip state controller', () => {
tooltip._stateController = { open: sinon.spy(), close: sinon.spy() };
controller.open({ hover: true });
expect(tooltip._stateController.open).to.be.calledOnceWith({ hover: true });
});

it('should not open the tooltip state controller when the tooltip is disconnected', () => {
tooltip._stateController = { open: sinon.spy(), close: sinon.spy() };
tooltip.remove();
controller.open({ hover: true });
expect(tooltip._stateController.open).to.be.not.called;
});

it('should delegate close to the tooltip state controller', () => {
tooltip._stateController = { open: sinon.spy(), close: sinon.spy() };
controller.close(true);
expect(tooltip._stateController.close).to.be.calledOnceWith(true);
});
});

describe('lazy tooltip', () => {
Expand Down Expand Up @@ -139,18 +150,6 @@ describe('TooltipController', () => {
expect(tooltip.manual).to.be.false;
});

it('should update lazy tooltip opened using controller setOpened method', async () => {
controller.setOpened(true);

host.appendChild(tooltip);
await nextFrame();

expect(tooltip.opened).to.be.true;

controller.setOpened(false);
expect(tooltip.opened).to.be.false;
});

it('should update lazy tooltip shouldShow using controller shouldShow method', async () => {
const shouldShow = () => true;
controller.setShouldShow(shouldShow);
Expand Down Expand Up @@ -238,5 +237,13 @@ describe('TooltipController', () => {
await nextFrame();
expect(host.hasAttribute('has-tooltip')).to.be.false;
});

it('should not throw when calling open before a tooltip is slotted', () => {
expect(() => controller.open({ hover: true })).to.not.throw();
});

it('should not throw when calling close before a tooltip is slotted', () => {
expect(() => controller.close(true)).to.not.throw();
});
});
});
7 changes: 2 additions & 5 deletions packages/grid/src/vaadin-grid-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ export const GridMixin = (superClass) =>
this._tooltipController.setContext(this.getEventContext(event));

// Trigger opening using the corresponding delay.
tooltip._stateController.open({
this._tooltipController.open({
focus: event.type === 'focusin',
hover: event.type === 'mouseenter',
});
Expand Down Expand Up @@ -918,10 +918,7 @@ export const GridMixin = (superClass) =>

/** @protected */
_hideTooltip(immediate) {
const tooltip = this._tooltipController && this._tooltipController.node;
if (tooltip) {
tooltip._stateController.close(immediate);
}
this._tooltipController.close(immediate);
}

/**
Expand Down
18 changes: 10 additions & 8 deletions packages/menu-bar/src/vaadin-menu-bar-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { I18nMixin } from '@vaadin/component-base/src/i18n-mixin.js';
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';

/**
* Custom Lit directive for rendering item components
Expand Down Expand Up @@ -310,12 +311,16 @@ export const MenuBarMixin = (superClass) =>
},
});

this.addController(this._subMenuController);
this.addController(this._overflowController);
this._tooltipController = new TooltipController(this);
this._tooltipController.setManual(true);

this.addEventListener('mousedown', () => this._hideTooltip(true));
this.addEventListener('mouseleave', () => this._hideTooltip());

this.addController(this._tooltipController);
this.addController(this._subMenuController);
this.addController(this._overflowController);

this._container = this.shadowRoot.querySelector('[part="container"]');
}

Expand Down Expand Up @@ -662,7 +667,7 @@ export const MenuBarMixin = (superClass) =>
this._tooltipController.setContext({ item: button.item });

// Trigger opening using the corresponding delay.
tooltip._stateController.open({
this._tooltipController.open({
hover: isHover,
focus: !isHover,
});
Expand All @@ -672,11 +677,8 @@ export const MenuBarMixin = (superClass) =>

/** @protected */
_hideTooltip(immediate) {
const tooltip = this._tooltipController && this._tooltipController.node;
if (tooltip) {
this._tooltipController.setContext({ item: null });
tooltip._stateController.close(immediate);
}
this._tooltipController.setContext({ item: null });
this._tooltipController.close(immediate);
}

/** @private */
Expand Down
10 changes: 0 additions & 10 deletions packages/menu-bar/src/vaadin-menu-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { menuBarStyles } from './styles/vaadin-menu-bar-base-styles.js';
Expand Down Expand Up @@ -97,15 +96,6 @@ class MenuBar extends MenuBarMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoI
`;
}

/** @protected */
ready() {
super.ready();

this._tooltipController = new TooltipController(this);
this._tooltipController.setManual(true);
this.addController(this._tooltipController);
}

/**
* Fired when either a submenu item or menu bar button without nested children is clicked.
*
Expand Down
12 changes: 0 additions & 12 deletions test/integration/grid-tooltip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,6 @@ describe('tooltip', () => {

expect(spy.calledOnce).to.be.false;
});

it('should not set tooltip opened if there is no tooltip', async () => {
const spy = sinon.spy(grid._tooltipController, 'setOpened');

tooltip.remove();
await nextFrame();

const cell = getCell(grid, 0);
mouseenter(cell);

expect(spy.calledOnce).to.be.false;
});
});

describe('cell not fully visible', () => {
Expand Down
2 changes: 0 additions & 2 deletions test/integration/menu-bar-tooltip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ describe('menu-bar with tooltip', () => {
it('should not set tooltip properties if there is no tooltip', async () => {
const spyTarget = sinon.spy(menuBar._tooltipController, 'setTarget');
const spyContent = sinon.spy(menuBar._tooltipController, 'setContext');
const spyOpened = sinon.spy(menuBar._tooltipController, 'setOpened');

tooltip.remove();
await nextRender();
Expand All @@ -203,7 +202,6 @@ describe('menu-bar with tooltip', () => {

expect(spyTarget.called).to.be.false;
expect(spyContent.called).to.be.false;
expect(spyOpened.called).to.be.false;
});

it('should not override a custom generator', () => {
Expand Down
Loading