From 9f034f331cc61cf5fa2b9d92e2d814321ddd8d44 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 20 Jun 2018 14:11:43 -0600 Subject: [PATCH 1/5] Fix tooltip re-position after a content resize, respect cntainer boundary+scroll bars --- src/components/tool_tip/tool_tip.js | 11 +++++++++- src/services/popover/popover_positioning.js | 20 +++++++++++++++---- .../popover/popover_positioning.test.js | 4 ++-- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/components/tool_tip/tool_tip.js b/src/components/tool_tip/tool_tip.js index e374aa460c2..929d2e57edc 100644 --- a/src/components/tool_tip/tool_tip.js +++ b/src/components/tool_tip/tool_tip.js @@ -37,6 +37,15 @@ export class EuiToolTip extends Component { setPopoverRef = ref => { this.popover = ref; + + // if the popover has been unmounted, clear + // any previous knowledge about its size + if (ref == null) { + this.setState({ + toolTipStyles: {}, + arrowStyles: {} + }); + } } showToolTip = () => { @@ -52,7 +61,7 @@ export class EuiToolTip extends Component { position: requestedPosition, offset: 16, // offset popover 16px from the anchor arrowConfig: { - arrowWidth: 14, + arrowWidth: 12, arrowBuffer: 4 } }); diff --git a/src/services/popover/popover_positioning.js b/src/services/popover/popover_positioning.js index 1dc4a204c81..484bff2709f 100644 --- a/src/services/popover/popover_positioning.js +++ b/src/services/popover/popover_positioning.js @@ -51,13 +51,17 @@ export function findPopoverPosition({ anchor, popover, position, buffer = 16, of const containerBoundingBox = getElementBoundingBox(container); // calculate the window's bounds + // window.(innerWidth|innerHeight) do not account for scrollbars + // so prefer the clientWidth/clientHeight of the DOM if available + const documentWidth = document.documentElement.clientWidth || window.innerWidth; + const documentHeight = document.documentElement.clientHeight || window.innerHeight; const windowBoundingBox = { top: 0, - right: window.innerWidth, - bottom: window.innerHeight, + right: documentWidth, + bottom: documentHeight, left: 0, - height: window.innerHeight, - width: window.innerWidth + height: documentHeight, + width: documentWidth }; /** @@ -236,6 +240,14 @@ export function getPopoverScreenCoordinates({ // calculate the fit of the popover in this location // fit is in range 0.0 -> 1.0 and is the percentage of the popover which is visible in this location const combinedBoundingBox = intersectBoundingBoxes(windowBoundingBox, containerBoundingBox); + + // shrink the visible bounding box by `buffer` + // to compute a fit value + combinedBoundingBox.top += buffer; + combinedBoundingBox.right -= buffer; + combinedBoundingBox.bottom -= buffer; + combinedBoundingBox.left += buffer; + const fit = getVisibleFit( { top: popoverPlacement.top, diff --git a/src/services/popover/popover_positioning.test.js b/src/services/popover/popover_positioning.test.js index 49162964432..7c57ac26be7 100644 --- a/src/services/popover/popover_positioning.test.js +++ b/src/services/popover/popover_positioning.test.js @@ -371,7 +371,7 @@ describe('popover_positioning', () => { // give the container limited space on both left and top, forcing to bottom-right const container = document.createElement('div'); - container.getBoundingClientRect = () => makeBB(100, 300, 768, 30); + container.getBoundingClientRect = () => makeBB(50, 300, 768, 30); expect(findPopoverPosition({ position: 'left', @@ -382,7 +382,7 @@ describe('popover_positioning', () => { })).toEqual({ fit: 1, position: 'right', - top: 100, + top: 85, left: 155 }); }); From cb86eb26511c48753c556a27353ee351762392ed Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 20 Jun 2018 14:19:09 -0600 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d58567d577c..636a945594a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ - Added `getPopoverScreenCoordinates` service function for positioining popover/tooltip content, updated `EuiToolTip` to use it ([#924](https://github.com/elastic/eui/pull/924)) - Allow `mode` prop in `EuiCodeEditor` to take custom mode object ([#935](https://github.com/elastic/eui/pull/935)) +**Bug fixes** + +- `EuiTooltip` re-positions content correctly after the window is resized ([#936](https://github.com/elastic/eui/pull/936)) + ## [`0.0.54`](https://github.com/elastic/eui/tree/v0.0.54) **Bug fixes** From 5c1e7b3724a958f5460663daa232f15d80a8ec96 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Thu, 21 Jun 2018 10:39:45 -0600 Subject: [PATCH 3/5] Change initial EuiTooltip content to avoid creating scrollbars --- src/components/tool_tip/tool_tip.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/tool_tip/tool_tip.js b/src/components/tool_tip/tool_tip.js index 929d2e57edc..f60fc16e757 100644 --- a/src/components/tool_tip/tool_tip.js +++ b/src/components/tool_tip/tool_tip.js @@ -21,6 +21,16 @@ const positionsToClassNameMap = { export const POSITIONS = Object.keys(positionsToClassNameMap); +const DEFAULT_TOOLTIP_STYLES = { + // position the tooltip content near the top-left + // corner of the window so it can't create scrollbars + top: 50, + left: 50, + // just in case, avoid any potential flicker by hiding + // the tooltip before it is positioned + opacity: 0 +}; + export class EuiToolTip extends Component { constructor(props) { super(props); @@ -29,7 +39,7 @@ export class EuiToolTip extends Component { visible: false, hasFocus: false, calculatedPosition: this.props.position, - toolTipStyles: {}, + toolTipStyles: DEFAULT_TOOLTIP_STYLES, arrowStyles: {}, id: this.props.id || makeId(), }; @@ -42,7 +52,7 @@ export class EuiToolTip extends Component { // any previous knowledge about its size if (ref == null) { this.setState({ - toolTipStyles: {}, + toolTipStyles: DEFAULT_TOOLTIP_STYLES, arrowStyles: {} }); } From 289289699f22884e1cad65701a8c6241b684c0d9 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Thu, 21 Jun 2018 15:15:33 -0600 Subject: [PATCH 4/5] Make position service container element optional --- src/components/tool_tip/tool_tip.js | 1 + src/services/popover/popover_positioning.js | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/tool_tip/tool_tip.js b/src/components/tool_tip/tool_tip.js index f60fc16e757..aa6b1ac0155 100644 --- a/src/components/tool_tip/tool_tip.js +++ b/src/components/tool_tip/tool_tip.js @@ -24,6 +24,7 @@ export const POSITIONS = Object.keys(positionsToClassNameMap); const DEFAULT_TOOLTIP_STYLES = { // position the tooltip content near the top-left // corner of the window so it can't create scrollbars + // 50,50 because who knows what negative margins, padding, etc top: 50, left: 50, // just in case, avoid any potential flicker by hiding diff --git a/src/services/popover/popover_positioning.js b/src/services/popover/popover_positioning.js index 484bff2709f..bc0eea27cbe 100644 --- a/src/services/popover/popover_positioning.js +++ b/src/services/popover/popover_positioning.js @@ -36,19 +36,18 @@ const positionSubstitutes = { * @param position {string} Position the user wants. One of ["top", "right", "bottom", "left"] * @param [buffer=16] {number} Minimum distance between the popover and the bounding container * @param [offset=0] {number} Distance between the popover and the anchor - * @param [container=document.body] {HTMLElement|React.Component} Element the popover must be constrained to fit within - * * @param [arrowConfig] {{arrowWidth: number, arrowBuffer: number}} If present, describes the size & constraints for an arrow element, and the function return value will include an `arrow` param with position details + * @param [container] {HTMLElement|React.Component} Element the popover must be constrained to fit within + * @param [arrowConfig] {{arrowWidth: number, arrowBuffer: number}} If present, describes the size & constraints for an arrow element, and the function return value will include an `arrow` param with position details * * @returns {{top: number, left: number, position: string, fit: number, arrow?: {left: number, top: number}}|null} absolute page coordinates for the popover, * and the placements's relation to the anchor; if there's no room this returns null */ -export function findPopoverPosition({ anchor, popover, position, buffer = 16, offset = 0, container = document.body, arrowConfig }) { +export function findPopoverPosition({ anchor, popover, position, buffer = 16, offset = 0, container, arrowConfig }) { container = findDOMNode(container); // resolve any React abstractions // find the screen-relative bounding boxes of the anchor, popover, and container const anchorBoundingBox = getElementBoundingBox(anchor); const popoverBoundingBox = getElementBoundingBox(popover); - const containerBoundingBox = getElementBoundingBox(container); // calculate the window's bounds // window.(innerWidth|innerHeight) do not account for scrollbars @@ -64,6 +63,9 @@ export function findPopoverPosition({ anchor, popover, position, buffer = 16, of width: documentWidth }; + // if no container element is given fall back to using the window viewport + const containerBoundingBox = container ? getElementBoundingBox(container) : windowBoundingBox; + /** * `position` was specified by the function caller and is a strong hint * as to the preferred location of the popover relative to the anchor. From d1a9466878e8c8e885e066a7be61e88526347d06 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 22 Jun 2018 10:01:06 -0600 Subject: [PATCH 5/5] updated changelog --- CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f2f404aeea..ded931ab72f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [`master`](https://github.com/elastic/eui/tree/master) -No public interface changes since `0.0.55`. +**Bug fixes** + +- `EuiTooltip` re-positions content correctly after the window is resized ([#936](https://github.com/elastic/eui/pull/936)) ## [`0.0.55`](https://github.com/elastic/eui/tree/v0.0.55) @@ -9,10 +11,6 @@ No public interface changes since `0.0.55`. - `EuiCodeEditor` is now decorated with a `data-test-subj` selector (`codeEditorContainer`) ([#939](https://github.com/elastic/eui/pull/939)) - `EuiCodeEditor` no longer automatically scrolls cursor into view on selection change ([#940](https://github.com/elastic/eui/pull/940)) -**Bug fixes** - -- `EuiTooltip` re-positions content correctly after the window is resized ([#936](https://github.com/elastic/eui/pull/936)) - ## [`0.0.54`](https://github.com/elastic/eui/tree/v0.0.54) **Bug fixes**