From 699b3fa2dc7be4e4b47498cedaaa7c8019281292 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Mon, 9 Jan 2023 16:33:10 -0800 Subject: [PATCH 1/3] Add `repositionOnScroll` prop and event listener --- src/components/tool_tip/tool_tip.test.tsx | 25 +++++++++++++++++++++++ src/components/tool_tip/tool_tip.tsx | 21 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/components/tool_tip/tool_tip.test.tsx b/src/components/tool_tip/tool_tip.test.tsx index ebbefd185ab..1f5b75c12e0 100644 --- a/src/components/tool_tip/tool_tip.test.tsx +++ b/src/components/tool_tip/tool_tip.test.tsx @@ -122,4 +122,29 @@ describe('EuiToolTip', () => { expect(container).toMatchSnapshot(); }); + + test('repositionOnScroll', () => { + const addEventSpy = jest.spyOn(window, 'addEventListener'); + const removeEventSpy = jest.spyOn(window, 'removeEventListener'); + const repositionFn = expect.any(Function); + + const { rerender, unmount } = render( + + + + ); + expect(addEventSpy).not.toHaveBeenCalledWith('scroll', expect.anything()); + + // Should add a scroll event listener on mount and on update + rerender( + + + + ); + expect(addEventSpy).toHaveBeenCalledWith('scroll', repositionFn, true); + + // Should remove the scroll event listener on unmount + unmount(); + expect(removeEventSpy).toHaveBeenCalledWith('scroll', repositionFn, true); + }); }); diff --git a/src/components/tool_tip/tool_tip.tsx b/src/components/tool_tip/tool_tip.tsx index f1cc8cc423d..e385271e2c2 100644 --- a/src/components/tool_tip/tool_tip.tsx +++ b/src/components/tool_tip/tool_tip.tsx @@ -108,6 +108,13 @@ export interface EuiToolTipProps { * Suggested position. If there is not enough room for it this will be changed. */ position: ToolTipPositions; + /** + * When `true`, the tooltip's position is re-calculated when the user + * scrolls. This supports having fixed-position tooltip anchors. + * + * When nesting an `EuiTooltip` in a scrollable container, `repositionOnScroll` should be `true` + */ + repositionOnScroll?: boolean; /** * If supplied, called when mouse movement causes the tool tip to be @@ -154,17 +161,30 @@ export class EuiToolTip extends Component { componentDidMount() { this._isMounted = true; + if (this.props.repositionOnScroll) { + window.addEventListener('scroll', this.positionToolTip, true); + } } componentWillUnmount() { this.clearAnimationTimeout(); this._isMounted = false; + window.removeEventListener('scroll', this.positionToolTip, true); } componentDidUpdate(prevProps: EuiToolTipProps, prevState: State) { if (prevState.visible === false && this.state.visible === true) { requestAnimationFrame(this.testAnchor); } + + // update scroll listener + if (prevProps.repositionOnScroll !== this.props.repositionOnScroll) { + if (this.props.repositionOnScroll) { + window.addEventListener('scroll', this.positionToolTip, true); + } else { + window.removeEventListener('scroll', this.positionToolTip, true); + } + } } testAnchor = () => { @@ -293,6 +313,7 @@ export class EuiToolTip extends Component { title, delay, display, + repositionOnScroll, ...rest } = this.props; From 2357159a579b6d847621418cff23fcb8d0b66040 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Mon, 9 Jan 2023 16:38:46 -0800 Subject: [PATCH 2/3] [Docs] Add fixed tooltip example + add auto-focus behavior for keyboard users --- .../src/views/tool_tip/tool_tip_example.js | 22 +++++++++++ .../src/views/tool_tip/tool_tip_fixed.tsx | 38 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src-docs/src/views/tool_tip/tool_tip_fixed.tsx diff --git a/src-docs/src/views/tool_tip/tool_tip_example.js b/src-docs/src/views/tool_tip/tool_tip_example.js index 6bcba7cb86c..fa3f0d3fed5 100644 --- a/src-docs/src/views/tool_tip/tool_tip_example.js +++ b/src-docs/src/views/tool_tip/tool_tip_example.js @@ -36,6 +36,9 @@ const tooltipSnippet = [ import ToolTipComponent from './tool_tip_components'; const toolTipComponentSource = require('!!raw-loader!./tool_tip_components'); +import ToolTipFixed from './tool_tip_fixed'; +const toolTipFixedSource = require('!!raw-loader!./tool_tip_fixed'); + import IconTip from './icon_tip'; const infoTipSource = require('!!raw-loader!./icon_tip'); const infoTipSnippet = `, }, + { + title: 'Tooltip on a fixed element', + text: ( +

+ Tooltips even work on position: fixed; elements. + Add the repositionOnScroll boolean prop to ensure + the tooltip realigns to the fixed anchor on scroll. +

+ ), + source: [ + { + type: GuideSectionTypes.TSX, + code: toolTipFixedSource, + }, + ], + + props: { EuiToolTip }, + demo: , + }, { title: 'IconTip', text: ( diff --git a/src-docs/src/views/tool_tip/tool_tip_fixed.tsx b/src-docs/src/views/tool_tip/tool_tip_fixed.tsx new file mode 100644 index 00000000000..289b993c98e --- /dev/null +++ b/src-docs/src/views/tool_tip/tool_tip_fixed.tsx @@ -0,0 +1,38 @@ +import React, { useState, useRef } from 'react'; + +import { EuiToolTip, EuiButton } from '../../../../src'; + +export default () => { + const toggleRef = useRef(null); + const fixedRef = useRef(null); + const [isExampleShown, setIsExampleShown] = useState(false); + const toggleExample = () => { + setIsExampleShown((isExampleShown) => { + requestAnimationFrame(() => { + isExampleShown ? toggleRef.current?.focus() : fixedRef.current?.focus(); + }); + return !isExampleShown; + }); + }; + + return ( + <> + + Toggle fixed example + + {isExampleShown && ( +
+ + + Toggle fixed example + + +
+ )} + + ); +}; From 1c2f55dfdd4fb3e04da8f52c6674560199a2bbc6 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Mon, 9 Jan 2023 16:43:32 -0800 Subject: [PATCH 3/3] changelog --- upcoming_changelogs/6515.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 upcoming_changelogs/6515.md diff --git a/upcoming_changelogs/6515.md b/upcoming_changelogs/6515.md new file mode 100644 index 00000000000..2d3ddb0a06d --- /dev/null +++ b/upcoming_changelogs/6515.md @@ -0,0 +1 @@ +- Added the `repositionOnScroll` prop to `EuiToolTip`