diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 9a245d85ebf849..a21e0f23334e1a 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -10,9 +10,10 @@ - `PaletteEdit` and `CircularOptionPicker`: improve unit tests ([#57809](https://github.com/WordPress/gutenberg/pull/57809)). - `Tooltip`: no-op when nested inside other `Tooltip` components ([#57202](https://github.com/WordPress/gutenberg/pull/57202)). -### Bug Fixes +### Bug Fix - `ToggleGroupControl`: Improve controlled value detection ([#57770](https://github.com/WordPress/gutenberg/pull/57770)). +- `Tooltip`: Improve props forwarding to children of nested `Tooltip` components ([#57878](https://github.com/WordPress/gutenberg/pull/57878)). ### Experimental diff --git a/packages/components/src/tooltip/index.tsx b/packages/components/src/tooltip/index.tsx index 1e652d9a42dbb4..f71182b85edb2c 100644 --- a/packages/components/src/tooltip/index.tsx +++ b/packages/components/src/tooltip/index.tsx @@ -8,34 +8,39 @@ import * as Ariakit from '@ariakit/react'; * WordPress dependencies */ import { useInstanceId } from '@wordpress/compose'; -import { Children, cloneElement } from '@wordpress/element'; +import { + Children, + useContext, + createContext, + forwardRef, +} from '@wordpress/element'; import deprecated from '@wordpress/deprecated'; /** * Internal dependencies */ -import type { TooltipProps, TooltipInternalContext } from './types'; +import type { + TooltipProps, + TooltipInternalContext as TooltipInternalContextType, +} from './types'; import Shortcut from '../shortcut'; import { positionToPlacement } from '../popover/utils'; -import { - contextConnect, - useContextSystem, - ContextSystemProvider, -} from '../context'; import type { WordPressComponentProps } from '../context'; +const TooltipInternalContext = createContext< TooltipInternalContextType >( { + isNestedInTooltip: false, +} ); + /** * Time over anchor to wait before showing tooltip */ export const TOOLTIP_DELAY = 700; const CONTEXT_VALUE = { - Tooltip: { - isNestedInTooltip: true, - }, + isNestedInTooltip: true, }; -function UnconnectedTooltip( +function UnforwardedTooltip( props: WordPressComponentProps< TooltipProps, 'div', false >, ref: React.ForwardedRef< any > ) { @@ -48,14 +53,10 @@ function UnconnectedTooltip( shortcut, text, - // From Internal Context system - isNestedInTooltip, - ...restProps - } = useContextSystem< typeof props & TooltipInternalContext >( - props, - 'Tooltip' - ); + } = props; + + const { isNestedInTooltip } = useContext( TooltipInternalContext ); const baseId = useInstanceId( Tooltip, 'tooltip' ); const describedById = text || shortcut ? baseId : undefined; @@ -96,16 +97,15 @@ function UnconnectedTooltip( } ); if ( isNestedInTooltip ) { - return isOnlyChild - ? cloneElement( children, { - ...restProps, - ref, - } ) - : children; + return isOnlyChild ? ( + + ) : ( + children + ); } return ( - + ) } - + ); } -export const Tooltip = contextConnect( UnconnectedTooltip, 'Tooltip' ); +export const Tooltip = forwardRef( UnforwardedTooltip ); export default Tooltip; diff --git a/packages/components/src/tooltip/test/index.tsx b/packages/components/src/tooltip/test/index.tsx index ed6f7b5f7b4a14..40038bbc5e25ad 100644 --- a/packages/components/src/tooltip/test/index.tsx +++ b/packages/components/src/tooltip/test/index.tsx @@ -102,6 +102,17 @@ describe( 'Tooltip', () => { screen.queryByRole( 'button', { description: 'tooltip text' } ) ).not.toBeInTheDocument(); } ); + + it( 'should not leak Tooltip props to the tooltip anchor', () => { + render( + + + + ); + expect( + screen.getByRole( 'button', { name: 'Anchor' } ) + ).not.toHaveAttribute( 'data-foo' ); + } ); } ); describe( 'keyboard focus', () => { diff --git a/packages/components/src/tooltip/types.ts b/packages/components/src/tooltip/types.ts index 3d28a1a0e96c67..11268683bc2ced 100644 --- a/packages/components/src/tooltip/types.ts +++ b/packages/components/src/tooltip/types.ts @@ -61,5 +61,5 @@ export type TooltipProps = { }; export type TooltipInternalContext = { - isNestedInTooltip?: boolean; + isNestedInTooltip: boolean; };