From 25c0eacc5116ad779d0b2df48f374da39ea9584f Mon Sep 17 00:00:00 2001 From: Guilherme Datilio Ribeiro Date: Mon, 26 Feb 2024 16:34:44 -0300 Subject: [PATCH] Added PolymorphicProps to `Link` (#15819) * fix: added PolymorphicProps to link * fix: fixed ref --------- Co-authored-by: Taylor Jones --- .../__snapshots__/PublicAPI-test.js.snap | 2 +- packages/react/src/components/Link/Link.tsx | 123 +++++++++--------- 2 files changed, 61 insertions(+), 64 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index bdd5de9de3b8..75e1c6b38f4b 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -4390,7 +4390,7 @@ Map { "$$typeof": Symbol(react.forward_ref), "propTypes": Object { "as": Object { - "type": "string", + "type": "elementType", }, "children": Object { "type": "node", diff --git a/packages/react/src/components/Link/Link.tsx b/packages/react/src/components/Link/Link.tsx index 6d78cb9784df..0bdf2335233d 100644 --- a/packages/react/src/components/Link/Link.tsx +++ b/packages/react/src/components/Link/Link.tsx @@ -11,18 +11,13 @@ import React, { AnchorHTMLAttributes, AriaAttributes, ComponentType, + ElementType, HTMLAttributeAnchorTarget, - PropsWithChildren, } from 'react'; import { usePrefix } from '../../internal/usePrefix'; +import { PolymorphicProps } from '../../types/common'; -export interface LinkProps extends AnchorHTMLAttributes { - /** - * Provide a custom element or component to render the top-level node for the - * component. - */ - as?: string | undefined; - +export interface LinkBaseProps extends AnchorHTMLAttributes { /** * @description Indicates the element that represents the * current item within a container or set of related @@ -73,60 +68,63 @@ export interface LinkProps extends AnchorHTMLAttributes { visited?: boolean; } -const Link = React.forwardRef>( - function Link( - { - as: BaseComponent, - children, - className: customClassName, - href, - disabled = false, - inline = false, - visited = false, - renderIcon: Icon, - size, - target, - ...rest - }, - ref - ) { - const prefix = usePrefix(); - const className = cx(`${prefix}--link`, customClassName, { - [`${prefix}--link--disabled`]: disabled, - [`${prefix}--link--inline`]: inline, - [`${prefix}--link--visited`]: visited, - [`${prefix}--link--${size}`]: size, - }); - const rel = target === '_blank' ? 'noopener' : undefined; - const linkProps: AnchorHTMLAttributes = { - className: BaseComponent ? undefined : className, - rel, - target, - }; - - // Reference for disabled links: - // https://www.scottohara.me/blog/2021/05/28/disabled-links.html - if (!disabled) { - linkProps.href = href; - } else { - linkProps.role = 'link'; - linkProps['aria-disabled'] = true; - } - - const BaseComponentAsAny = (BaseComponent ?? 'a') as any; - - return ( - - {children} - {!inline && Icon && ( -
- -
- )} -
- ); +export type LinkProps = PolymorphicProps< + E, + LinkBaseProps +>; + +const Link = React.forwardRef(function Link( + { + as: BaseComponent, + children, + className: customClassName, + href, + disabled = false, + inline = false, + visited = false, + renderIcon: Icon, + size, + target, + ...rest + }: LinkProps, + ref +) { + const prefix = usePrefix(); + const className = cx(`${prefix}--link`, customClassName, { + [`${prefix}--link--disabled`]: disabled, + [`${prefix}--link--inline`]: inline, + [`${prefix}--link--visited`]: visited, + [`${prefix}--link--${size}`]: size, + }); + const rel = target === '_blank' ? 'noopener' : undefined; + const linkProps: AnchorHTMLAttributes = { + className: BaseComponent ? undefined : className, + rel, + target, + }; + + // Reference for disabled links: + // https://www.scottohara.me/blog/2021/05/28/disabled-links.html + if (!disabled) { + linkProps.href = href; + } else { + linkProps.role = 'link'; + linkProps['aria-disabled'] = true; } -); + + const BaseComponentAsAny = (BaseComponent ?? 'a') as any; + + return ( + + {children} + {!inline && Icon && ( +
+ +
+ )} +
+ ); +}); Link.displayName = 'Link'; @@ -135,7 +133,7 @@ Link.propTypes = { * Provide a custom element or component to render the top-level node for the * component. */ - as: PropTypes.string, + as: PropTypes.elementType, /** * Provide the content for the Link @@ -166,7 +164,6 @@ Link.propTypes = { * Optional prop to render an icon next to the link. * Can be a React component class */ - // @ts-expect-error - PropTypes are unable to cover this case. renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /**