Skip to content

Commit

Permalink
new(tooltip, xychart): force update TooltipInPortal bounds (#1045)
Browse files Browse the repository at this point in the history
* new(tooltip/useTooltipInPortal): expose forceRefreshBounds

* new(xychart/Tooltip): force update tooltip parent bounds when tooltip becomes visible

* test(xychart/Tooltip): fix test
  • Loading branch information
williaster authored Feb 4, 2021
1 parent 1d94cf9 commit 078ca18
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 4 deletions.
4 changes: 3 additions & 1 deletion packages/visx-tooltip/src/hooks/useTooltipInPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type TooltipInPortalProps = TooltipProps & Pick<UseTooltipPortalOptions,
export type UseTooltipInPortal = {
containerRef: (element: HTMLElement | SVGElement | null) => void;
containerBounds: RectReadOnly;
forceRefreshBounds: () => void;
TooltipInPortal: React.FC<TooltipInPortalProps>;
};

Expand All @@ -32,7 +33,7 @@ export default function useTooltipInPortal({
detectBounds: detectBoundsOption = true,
...useMeasureOptions
}: UseTooltipPortalOptions | undefined = {}): UseTooltipInPortal {
const [containerRef, containerBounds] = useMeasure(useMeasureOptions);
const [containerRef, containerBounds, forceRefreshBounds] = useMeasure(useMeasureOptions);

const TooltipInPortal = useMemo(
() => ({
Expand Down Expand Up @@ -61,6 +62,7 @@ export default function useTooltipInPortal({
// @ts-ignore fixed here https://github.com/react-spring/react-use-measure/pull/17
containerRef,
containerBounds,
forceRefreshBounds,
TooltipInPortal,
};
}
17 changes: 15 additions & 2 deletions packages/visx-xychart/src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useContext } from 'react';
import React, { useCallback, useContext, useEffect, useRef } from 'react';
import { useTooltipInPortal, defaultStyles } from '@visx/tooltip';
import { TooltipProps as BaseTooltipProps } from '@visx/tooltip/lib/tooltips/Tooltip';
import { PickD3Scale } from '@visx/scale';
Expand Down Expand Up @@ -93,7 +93,7 @@ export default function Tooltip<Datum extends object>({
const { colorScale, theme, innerHeight, innerWidth, margin, xScale, yScale, dataRegistry } =
useContext(DataContext) || {};
const tooltipContext = useContext(TooltipContext) as TooltipContextType<Datum>;
const { containerRef, TooltipInPortal } = useTooltipInPortal({
const { containerRef, TooltipInPortal, forceRefreshBounds } = useTooltipInPortal({
debounce,
detectBounds,
polyfill: resizeObserverPolyfill,
Expand All @@ -115,6 +115,19 @@ export default function Tooltip<Datum extends object>({

const showTooltip = tooltipContext?.tooltipOpen && tooltipContent != null;

// useTooltipInPortal is powered by react-use-measure and will update portal positions upon
// resize and page scroll. however it **cannot** detect when a chart container moves on a
// page due to animation or drag-and-drop, etc.
// therefore we force refresh the bounds any time we transition from a hidden tooltip to
// one that is visible.
const lastShowTooltip = useRef(false);
useEffect(() => {
if (showTooltip && !lastShowTooltip.current) {
forceRefreshBounds();
}
lastShowTooltip.current = showTooltip;
}, [showTooltip, forceRefreshBounds]);

let tooltipLeft = tooltipContext?.tooltipLeft;
let tooltipTop = tooltipContext?.tooltipTop;

Expand Down
2 changes: 1 addition & 1 deletion packages/visx-xychart/test/components/Tooltip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('<Tooltip />', () => {
props: { renderTooltip },
context: { tooltipOpen: true },
});
expect(renderTooltip).toHaveBeenCalledTimes(1);
expect(renderTooltip).toHaveBeenCalled(); // may be invoked more than once due to forceRefreshBounds invocation
});

it('should render a vertical crosshair if showVerticalCrossHair=true', () => {
Expand Down

0 comments on commit 078ca18

Please sign in to comment.