Fix external links

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-07-14 15:29:24 +02:00
parent b692eff10b
commit 8ecf4568c9
3 changed files with 42 additions and 2 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
'@backstage/canon': minor
---
**Breaking changes** We are updating our Link component to use React Aria under the hood. To match their API we are updating the `to` prop to `href` to match both internal and expernal routing. We are also updating our variant naming to include all our new font sizes.
**Breaking changes** We are updating our Link component to use React Aria under the hood. To match their API we are updating the `to` prop to `href` to match both internal and external routing. We are also updating our variant naming to include all our new font sizes.
@@ -40,7 +40,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
href: '#',
href: '/home',
children: 'Sign up for Backstage',
},
};
@@ -21,6 +21,28 @@ import { useStyles } from '../../hooks/useStyles';
import type { LinkProps } from './types';
import { useNavigate, useHref } from 'react-router-dom';
// Helper function to determine if a link is external
function isExternalLink(href?: string): boolean {
if (!href) return false;
// Check if it's an absolute URL with protocol
if (href.startsWith('http://') || href.startsWith('https://')) {
return true;
}
// Check if it's a protocol-relative URL
if (href.startsWith('//')) {
return true;
}
// Check if it's a mailto: or tel: link
if (href.startsWith('mailto:') || href.startsWith('tel:')) {
return true;
}
return false;
}
/** @public */
export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
const navigate = useNavigate();
@@ -29,6 +51,7 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
variant = 'body',
weight = 'regular',
color = 'primary',
href,
...restProps
} = props;
@@ -38,11 +61,28 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
color,
});
const isExternal = isExternalLink(href);
// If it's an external link, render AriaLink without RouterProvider
if (isExternal) {
return (
<AriaLink
ref={ref}
className={clsx(classNames.root, className)}
href={href}
{...dataAttributes}
{...restProps}
/>
);
}
// For internal links, use RouterProvider
return (
<RouterProvider navigate={navigate} useHref={useHref}>
<AriaLink
ref={ref}
className={clsx(classNames.root, className)}
href={href}
{...dataAttributes}
{...restProps}
/>