diff --git a/CHANGELOG.md b/CHANGELOG.md index 3916c839f..daae195b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - [#841](https://github.com/plotly/dash-table/pull/841) - Fix prop-types regression causing console errors in browser devtools - Fix syntax highlighting regression for Markdown cells +- [#842](https://github.com/plotly/dash-table/pull/842) Fix a regression introduced with [#722](https://github.com/plotly/dash-table/pull/722) causing the tooltips to be misaligned with respect to their parent cell and incompletely addressed in [#817](https://github.com/plotly/dash-table/pull/817) ### Added - [#841](https://github.com/plotly/dash-table/pull/841) Add Julia syntax highlighting support for Markdown cells diff --git a/src/dash-table/components/ControlledTable/fragments/TableTooltip.tsx b/src/dash-table/components/ControlledTable/fragments/TableTooltip.tsx index 1f04b5393..e0d31a1a6 100644 --- a/src/dash-table/components/ControlledTable/fragments/TableTooltip.tsx +++ b/src/dash-table/components/ControlledTable/fragments/TableTooltip.tsx @@ -1,7 +1,7 @@ import React, {Component} from 'react'; import Tooltip, {ITooltipProps, Arrow} from 'dash-table/components/Tooltip'; -import tooltipHelper from 'dash-table/components/tooltipHelper'; +import {getPositionalParent} from 'dash-table/components/tooltipHelper'; import ReactDOM from 'react-dom'; import {isEqual} from 'core/comparer'; @@ -52,71 +52,52 @@ export default class TableTooltip extends Component { const el = ReactDOM.findDOMNode(this.refs.tooltip) as any; - const {positionalParent, parent} = tooltipHelper(el, cell); + const positionalParent = getPositionalParent(el); - if (!positionalParent || !parent || !el) { + if (!positionalParent || !cell || !el) { return; } const positionalBounds = positionalParent.getBoundingClientRect(); - const parentBounds = parent.getBoundingClientRect(); + const parentBounds = cell.getBoundingClientRect(); const {clientWidth: elWidth, clientHeight: elHeight} = el; + const elAnchorHeight = Math.max( parseFloat(getComputedStyle(el, ':before').borderWidth || '0'), parseFloat(getComputedStyle(el, ':after').borderWidth || '0') ); const leftCorrection = (parentBounds.width - elWidth) / 2; + let left = parentBounds.left - positionalBounds.left + positionalParent.scrollLeft + leftCorrection; + let top = parentBounds.top - positionalBounds.top + positionalParent.scrollTop + parentBounds.height; - const { - scrollLeft: vwLeft, - scrollTop: vwTop, - clientWidth: vwWidth, - clientHeight: vwHeight - } = document.body; - - let arrow: Arrow | undefined = Arrow.Top; + const leftmost = left + positionalBounds.left; + const rightmost = leftmost + elWidth; - let delta = 0; + const topmost = top + positionalBounds.top; + const bottommost = topmost + elHeight + elAnchorHeight; - // too far left - if (left < vwLeft) { - delta = vwLeft - left; - left = vwLeft; - } + let arrow: Arrow | undefined = Arrow.Top; - // too far right - if (left + elWidth > vwLeft + vwWidth) { - delta = vwLeft + vwWidth - elWidth - left; - left = vwLeft + vwWidth - elWidth; - } + left -= Math.min(0, leftmost); + left -= Math.max(0, rightmost - document.documentElement.clientWidth); - // too low - if (top + elHeight > vwTop + vwHeight) { - top = - parentBounds.top - - positionalBounds.top + - positionalParent.scrollTop - - (elHeight + elAnchorHeight); + if (bottommost > document.documentElement.clientHeight) { + top -= elHeight + elAnchorHeight + parentBounds.height; arrow = Arrow.Bottom; } - delta = Math.abs(delta); - if (delta > parent.clientWidth / 2) { - arrow = undefined; - } - el.style.top = `${top}px`; el.style.left = `${left}px`; el.style.position = 'absolute'; diff --git a/src/dash-table/components/tooltipHelper.ts b/src/dash-table/components/tooltipHelper.ts index 5f932a154..9b1b38255 100644 --- a/src/dash-table/components/tooltipHelper.ts +++ b/src/dash-table/components/tooltipHelper.ts @@ -1,18 +1,6 @@ -export default (el: HTMLElement | null, parent: HTMLElement | null = null) => { - parent = - parent || - (() => { - parent = el; - - while (parent && parent.nodeName.toLowerCase() !== 'td') { - parent = parent.parentElement; - } - - return parent; - })(); - - if (!el || !parent) { - return {}; +export const getPositionalParent = (el: HTMLElement | null = null) => { + if (!el) { + return; } let positionalParent = el; @@ -27,14 +15,5 @@ export default (el: HTMLElement | null, parent: HTMLElement | null = null) => { positionalParent = positionalParent.parentElement; } - let relativeParent = el; - while (getComputedStyle(relativeParent).position !== 'relative') { - if (!relativeParent.parentElement) { - break; - } - - relativeParent = relativeParent.parentElement; - } - - return {positionalParent, parent}; + return positionalParent; }; diff --git a/tests/selenium/test_tooltip.py b/tests/selenium/test_tooltip.py index 24527f04a..202fb725e 100644 --- a/tests/selenium/test_tooltip.py +++ b/tests/selenium/test_tooltip.py @@ -40,7 +40,11 @@ def assert_aligned(cell, tooltip): @pytest.mark.parametrize( "fixed_rows", - [dict(fixed_rows=dict(headers=True)), dict(fixed_rows=dict(headers=True, data=1))], + [ + dict(), + dict(fixed_rows=dict(headers=True)), + dict(fixed_rows=dict(headers=True, data=1)), + ], ) @pytest.mark.parametrize( "fixed_columns", @@ -73,7 +77,6 @@ def test_ttip001_displays_aligned_tooltip(test, fixed_rows, fixed_columns, ops): tooltip = target.tooltip target.is_ready() - cell.move_to() assert tooltip.exists() assert tooltip.get_text() == ";; 1-1"