From 62c1f50704d7b2235a525e121d5ee6ea0bc449e1 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 18 Sep 2023 16:32:25 +0800 Subject: [PATCH] Fix React forwardRef warnings for `TooltipAnchor`s (#54492) * Forward refs for SVG and Icon components * Address code review * Fix unit test * Add changelog --- packages/icons/CHANGELOG.md | 4 +++ packages/icons/src/icon/index.js | 14 +++++---- packages/primitives/CHANGELOG.md | 4 +++ packages/primitives/src/svg/index.js | 44 +++++++++++++++------------- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index 3c1715455ad497..ec07610cee52d4 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- `` now forwards ref to the underlying child component ([#54492](https://github.com/WordPress/gutenberg/pull/54492)). + ## 9.32.0 (2023-08-31) ### Bug Fix diff --git a/packages/icons/src/icon/index.js b/packages/icons/src/icon/index.js index e8bd1477dcd025..c83a5179a41b8e 100644 --- a/packages/icons/src/icon/index.js +++ b/packages/icons/src/icon/index.js @@ -1,25 +1,27 @@ /** * WordPress dependencies */ -import { cloneElement } from '@wordpress/element'; +import { cloneElement, forwardRef } from '@wordpress/element'; /** @typedef {{icon: JSX.Element, size?: number} & import('@wordpress/primitives').SVGProps} IconProps */ /** * Return an SVG icon. * - * @param {IconProps} props icon is the SVG component to render - * size is a number specifiying the icon size in pixels - * Other props will be passed to wrapped SVG component + * @param {IconProps} props icon is the SVG component to render + * size is a number specifiying the icon size in pixels + * Other props will be passed to wrapped SVG component + * @param {import('react').ForwardedRef} ref The forwarded ref to the SVG element. * * @return {JSX.Element} Icon component */ -function Icon( { icon, size = 24, ...props } ) { +function Icon( { icon, size = 24, ...props }, ref ) { return cloneElement( icon, { width: size, height: size, ...props, + ref, } ); } -export default Icon; +export default forwardRef( Icon ); diff --git a/packages/primitives/CHANGELOG.md b/packages/primitives/CHANGELOG.md index 6beb37c1b9dd8a..a762a52ffbf974 100644 --- a/packages/primitives/CHANGELOG.md +++ b/packages/primitives/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- `` now forwards ref to the underlying `` element ([#54492](https://github.com/WordPress/gutenberg/pull/54492)). + ## 3.39.0 (2023-08-31) ## 3.38.0 (2023-08-16) diff --git a/packages/primitives/src/svg/index.js b/packages/primitives/src/svg/index.js index 79a5e7f58e55d6..420432d0543e13 100644 --- a/packages/primitives/src/svg/index.js +++ b/packages/primitives/src/svg/index.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { createElement } from '@wordpress/element'; +import { createElement, forwardRef } from '@wordpress/element'; /** @typedef {{isPressed?: boolean} & import('react').ComponentPropsWithoutRef<'svg'>} SVGProps */ @@ -82,23 +82,27 @@ export const LinearGradient = ( props ) => */ export const Stop = ( props ) => createElement( 'stop', props ); -/** - * - * @param {SVGProps} props isPressed indicates whether the SVG should appear as pressed. - * Other props will be passed through to svg component. - * - * @return {JSX.Element} Stop component - */ -export const SVG = ( { className, isPressed, ...props } ) => { - const appliedProps = { - ...props, - className: - classnames( className, { 'is-pressed': isPressed } ) || undefined, - 'aria-hidden': true, - focusable: false, - }; +export const SVG = forwardRef( + /** + * @param {SVGProps} props isPressed indicates whether the SVG should appear as pressed. + * Other props will be passed through to svg component. + * @param {import('react').ForwardedRef} ref The forwarded ref to the SVG element. + * + * @return {JSX.Element} Stop component + */ + ( { className, isPressed, ...props }, ref ) => { + const appliedProps = { + ...props, + className: + classnames( className, { 'is-pressed': isPressed } ) || + undefined, + 'aria-hidden': true, + focusable: false, + }; - // Disable reason: We need to have a way to render HTML tag for web. - // eslint-disable-next-line react/forbid-elements - return ; -}; + // Disable reason: We need to have a way to render HTML tag for web. + // eslint-disable-next-line react/forbid-elements + return ; + } +); +SVG.displayName = 'SVG';