From 0d38b3a2520bb76034a1042b62867eb1a1bb1723 Mon Sep 17 00:00:00 2001 From: Serhii Kulykov Date: Wed, 4 Sep 2024 13:07:11 +0300 Subject: [PATCH] fix: only show tooltip if the target cell is fully visible (#7749) --- integration/tests/grid-tooltip.test.js | 62 ++++++++++++++++++++++++++ packages/grid/src/vaadin-grid-mixin.js | 35 ++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/integration/tests/grid-tooltip.test.js b/integration/tests/grid-tooltip.test.js index ef332cc265..95e793ea0a 100644 --- a/integration/tests/grid-tooltip.test.js +++ b/integration/tests/grid-tooltip.test.js @@ -32,6 +32,7 @@ describe('tooltip', () => { + `); @@ -262,6 +263,67 @@ describe('tooltip', () => { }); }); + describe('cell not fully visible', () => { + ['ltr', 'rtl'].forEach((direction) => { + describe(`${direction}`, () => { + const isRTL = direction === 'rtl'; + + before(() => { + document.documentElement.setAttribute('dir', direction); + }); + + after(() => { + document.documentElement.removeAttribute('dir'); + }); + + beforeEach(async () => { + tooltip.hoverDelay = 0; + grid.style.width = '150px'; + flushGrid(grid); + await nextRender(); + }); + + it('should not show tooltip when cell not fully visible at the start', async () => { + grid.$.table.scrollLeft = isRTL ? -150 : 150; + await nextRender(); + flushGrid(grid); + + mouseenter(getCell(grid, 0)); + expect(tooltip.opened).to.be.false; + }); + + it('should not show tooltip when cell not fully visible at the end', () => { + mouseenter(getCell(grid, 1)); + expect(tooltip.opened).to.be.false; + }); + + it('should not show tooltip when cell is partially covered by frozen cell', async () => { + grid.querySelector('vaadin-grid-column').frozen = true; + await nextRender(); + + grid.$.table.scrollLeft = isRTL ? -100 : 100; + await nextRender(); + flushGrid(grid); + + mouseenter(getCell(grid, 1)); + expect(tooltip.opened).to.be.false; + }); + + it('should not show tooltip when cell is partially covered by frozen to end cell', async () => { + grid.querySelectorAll('vaadin-grid-column')[2].frozenToEnd = true; + await nextRender(); + + grid.$.table.scrollLeft = isRTL ? -100 : 100; + await nextRender(); + flushGrid(grid); + + mouseenter(getCell(grid, 1)); + expect(tooltip.opened).to.be.false; + }); + }); + }); + }); + describe('delay', () => { before(() => { Tooltip.setDefaultFocusDelay(0); diff --git a/packages/grid/src/vaadin-grid-mixin.js b/packages/grid/src/vaadin-grid-mixin.js index 99bf814997..8bde43fb6a 100644 --- a/packages/grid/src/vaadin-grid-mixin.js +++ b/packages/grid/src/vaadin-grid-mixin.js @@ -1004,7 +1004,13 @@ export const GridMixin = (superClass) => // Check if there is a slotted vaadin-tooltip element. const tooltip = this._tooltipController.node; if (tooltip && tooltip.isConnected) { - this._tooltipController.setTarget(event.target); + const target = event.target; + + if (!this.__isCellFullyVisible(target)) { + return; + } + + this._tooltipController.setTarget(target); this._tooltipController.setContext(this.getEventContext(event)); // Trigger opening using the corresponding delay. @@ -1015,6 +1021,33 @@ export const GridMixin = (superClass) => } } + /** @private */ + __isCellFullyVisible(cell) { + if (cell.hasAttribute('frozen') || cell.hasAttribute('frozen-to-end')) { + // Frozen cells are always fully visible + return true; + } + + let { left, right } = this.getBoundingClientRect(); + + const frozen = [...cell.parentNode.children].find((cell) => cell.hasAttribute('last-frozen')); + if (frozen) { + const frozenRect = frozen.getBoundingClientRect(); + left = this.__isRTL ? left : frozenRect.right; + right = this.__isRTL ? frozenRect.left : right; + } + + const frozenToEnd = [...cell.parentNode.children].find((cell) => cell.hasAttribute('first-frozen-to-end')); + if (frozenToEnd) { + const frozenToEndRect = frozenToEnd.getBoundingClientRect(); + left = this.__isRTL ? frozenToEndRect.right : left; + right = this.__isRTL ? right : frozenToEndRect.left; + } + + const cellRect = cell.getBoundingClientRect(); + return cellRect.left >= left && cellRect.right <= right; + } + /** @protected */ _hideTooltip(immediate) { const tooltip = this._tooltipController && this._tooltipController.node;