diff --git a/api/charts.api.md b/api/charts.api.md index df06bd3bb9..b07f332842 100644 --- a/api/charts.api.md +++ b/api/charts.api.md @@ -1444,6 +1444,12 @@ export interface OrderBy { // @public (undocumented) export type OrdinalDomain = (number | string)[]; +// Warning: (ae-forgotten-export) The symbol "PerSideDistance" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "Padding" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type Padding = PerSideDistance; + // Warning: (ae-missing-release-tag) "PARENT_KEY" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -2221,6 +2227,7 @@ export interface TooltipInfo { // @public export interface TooltipPortalSettings { boundary?: HTMLElement | B; + boundaryPadding?: Partial | number; fallbackPlacements?: Placement[]; offset?: number; placement?: Placement; diff --git a/src/components/portal/tooltip_portal.tsx b/src/components/portal/tooltip_portal.tsx index 390ab3f426..89728ed7d4 100644 --- a/src/components/portal/tooltip_portal.tsx +++ b/src/components/portal/tooltip_portal.tsx @@ -22,6 +22,7 @@ import { useRef, useEffect, useCallback, ReactNode, useMemo } from 'react'; import { createPortal } from 'react-dom'; import { mergePartial, isDefined } from '../../utils/common'; +import { Padding } from '../../utils/dimensions'; import { TooltipPortalSettings, PortalAnchorRef } from './types'; import { DEFAULT_POPPER_SETTINGS, getOrCreateNode, isHTMLElement } from './utils'; @@ -56,6 +57,20 @@ type PortalTooltipProps = { chartId: string; }; +function addToPadding(padding?: Partial | number, extra: number = 0): Padding | number | undefined { + if (!padding) return undefined; + if (typeof padding === 'number') return padding + extra; + + const { top = 0, right = 0, bottom = 0, left = 0 } = padding; + + return { + top: top + extra, + right: right + extra, + bottom: bottom + extra, + left: left + extra, + }; +} + const TooltipPortalComponent = ({ anchor, scope, @@ -113,7 +128,7 @@ const TooltipPortalComponent = ({ return; } - const { fallbackPlacements, placement, boundary, offset } = popperSettings; + const { fallbackPlacements, placement, boundary, offset, boundaryPadding } = popperSettings; popper.current = createPopper(anchorNode.current, portalNode.current, { strategy: 'absolute', placement, @@ -128,6 +143,7 @@ const TooltipPortalComponent = ({ name: 'preventOverflow', options: { boundary, + padding: boundaryPadding, }, }, { @@ -138,7 +154,7 @@ const TooltipPortalComponent = ({ boundary, // checks main axis overflow before trying to flip altAxis: false, - padding: offset || 10, + padding: addToPadding(boundaryPadding, offset), }, }, ], diff --git a/src/components/portal/types.ts b/src/components/portal/types.ts index ec00997951..f8949e66a4 100644 --- a/src/components/portal/types.ts +++ b/src/components/portal/types.ts @@ -19,6 +19,8 @@ import { $Values } from 'utility-types'; +import { Padding } from '../../utils/dimensions'; + /** * Placement used in positioning tooltip * @public @@ -100,6 +102,13 @@ export interface TooltipPortalSettings { * @defaultValue parent scroll container */ boundary?: HTMLElement | B; + /** + * Boundary element padding. + * Used to reduce extents of boundary placement when magins or paddings are used on boundary + * + * @defaultValue 0 + */ + boundaryPadding?: Partial | number; /** * Custom tooltip offset */ diff --git a/src/index.ts b/src/index.ts index b33694894e..e59c1de9ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,7 +28,7 @@ export { DebugState } from './state/types'; export { toEntries } from './utils/common'; export { CurveType } from './utils/curves'; export { ContinuousDomain, OrdinalDomain } from './utils/domain'; -export { SimplePadding } from './utils/dimensions'; +export { SimplePadding, Padding } from './utils/dimensions'; export { timeFormatter, niceTimeFormatter, niceTimeFormatByDay } from './utils/data/formatters'; export { SeriesIdentifier, SeriesKey } from './common/series_id'; export { XYChartSeriesIdentifier, DataSeriesDatum, FilledValues } from './chart_types/xy_chart/utils/series'; diff --git a/stories/bar/55_tooltip_boundary.tsx b/stories/bar/55_tooltip_boundary.tsx index db9f8a428e..39cf20c22e 100644 --- a/stories/bar/55_tooltip_boundary.tsx +++ b/stories/bar/55_tooltip_boundary.tsx @@ -30,6 +30,7 @@ const rng = getRandomNumberGenerator(); export const Example = () => { const showAxes = boolean('Show axes', false); const groups = number('Groups', 5, { min: 2, max: 20, step: 1 }); + const offset = number('Offset', 10, { min: 0, step: 1 }); const data = dg.generateGroupedSeries(4, groups).map((d) => { return { ...d, @@ -42,7 +43,7 @@ export const Example = () => { const red = useRef(null); const white = useRef(null); const blue = useRef(null); - const boundaryMap: Record = { + const getBoundary: Record = { default: undefined, red: red.current, white: white.current, @@ -62,14 +63,20 @@ export const Example = () => { }, 'default', ); - const boundary = boundaryMap[boundarySting] ?? undefined; + const boundary = getBoundary[boundarySting] ?? undefined; + const boundaryPadding = { + top: number('Boundary top padding', 0, { min: 0 }), + right: number('Boundary right padding', 0, { min: 0 }), + bottom: number('Boundary bottom padding', 0, { min: 0 }), + left: number('Boundary left padding', 0, { min: 0 }), + }; return (
- +