Skip to content

Commit

Permalink
Added PolymorphicProps to Link (#15819)
Browse files Browse the repository at this point in the history
* fix: added PolymorphicProps to link

* fix: fixed ref

---------

Co-authored-by: Taylor Jones <[email protected]>
  • Loading branch information
guidari and tay1orjones authored Feb 26, 2024
1 parent e3c5faa commit 25c0eac
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4390,7 +4390,7 @@ Map {
"$$typeof": Symbol(react.forward_ref),
"propTypes": Object {
"as": Object {
"type": "string",
"type": "elementType",
},
"children": Object {
"type": "node",
Expand Down
123 changes: 60 additions & 63 deletions packages/react/src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLAnchorElement> {
/**
* Provide a custom element or component to render the top-level node for the
* component.
*/
as?: string | undefined;

export interface LinkBaseProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
/**
* @description Indicates the element that represents the
* current item within a container or set of related
Expand Down Expand Up @@ -73,60 +68,63 @@ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
visited?: boolean;
}

const Link = React.forwardRef<HTMLAnchorElement, PropsWithChildren<LinkProps>>(
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<HTMLAnchorElement> = {
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 (
<BaseComponentAsAny ref={ref} {...linkProps} {...rest}>
{children}
{!inline && Icon && (
<div className={`${prefix}--link__icon`}>
<Icon />
</div>
)}
</BaseComponentAsAny>
);
export type LinkProps<E extends ElementType> = PolymorphicProps<
E,
LinkBaseProps
>;

const Link = React.forwardRef(function Link<E extends React.ElementType>(
{
as: BaseComponent,
children,
className: customClassName,
href,
disabled = false,
inline = false,
visited = false,
renderIcon: Icon,
size,
target,
...rest
}: LinkProps<E>,
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<HTMLAnchorElement> = {
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 (
<BaseComponentAsAny ref={ref} {...linkProps} {...rest}>
{children}
{!inline && Icon && (
<div className={`${prefix}--link__icon`}>
<Icon />
</div>
)}
</BaseComponentAsAny>
);
});

Link.displayName = 'Link';

Expand All @@ -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
Expand Down Expand Up @@ -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]),

/**
Expand Down

0 comments on commit 25c0eac

Please sign in to comment.