Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Link): add react-router link integration #294

Merged
merged 4 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/components/Link/Link.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
import { BrowserRouter } from 'react-router-dom';
import {
DestructiveLink,
Icon,
Expand Down Expand Up @@ -137,3 +138,24 @@ export const JumpLinkIconLeft: Story = {
</Link>
)
};

export const LinkWithReactRouterLink: Story = {
name: 'Link using React Router Link',
parameters: {
docs: {
description: {
story:
'See [React Router Link docs](https://reactrouter.com/en/main/components/link) for usage information'
}
}
},
render: () => (
<BrowserRouter>
<p>
<Link href='/#' isRouterLink>
Link using React Router Link
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: after writing out everything below I realized that the fact that it is a CFPB styled Link is important to the name, so you can ignore the rest of this comment 😬


The naming feels a bit awkward. Since it's ultimately returning a RouterLink it would be easier to simply call this React Router Link.

That said, we've been adjusting naming of variants in other components (ex. Instead of "Checkboxes -> Large target area checkbox" using "Checkboxes -> Large target area" to leverage the context that implies that everything under the "Checkboxes" heading is a "checkbox") and the names for Link could probably use some improvement as well. So this is probably fine as-is and can be re-evaluated in the next round of naming reviews.

</Link>
</p>
</BrowserRouter>
)
};
35 changes: 28 additions & 7 deletions src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import classnames from 'classnames';
import { Link as RouterLink } from 'react-router-dom';
import type { JSXElement } from '../../types/jsxElement';

import classnames from 'classnames';
import ListItem from '../List/ListItem';

interface LinkProperties extends React.HTMLProps<HTMLAnchorElement> {
type?: 'default' | 'destructive' | 'list';
export interface LinkProperties extends React.HTMLProps<HTMLAnchorElement> {
children?: React.ReactNode;
hasIcon?: boolean;
noWrap?: boolean;
href?: string;
isJump?: boolean;
isJumpLeft?: boolean;
isRouterLink?: boolean;
noWrap?: boolean;
ref?: React.Ref<HTMLAnchorElement>;
type?: 'default' | 'destructive' | 'list';
}

/**
Expand All @@ -17,11 +23,13 @@ interface LinkProperties extends React.HTMLProps<HTMLAnchorElement> {
*/
export default function Link({
children,
type = 'default',
hasIcon = false,
noWrap = false,
href,
isJump = false,
isJumpLeft = false,
isRouterLink = false,
noWrap = false,
type = 'default',
...others
}: LinkProperties): JSXElement {
const cname = [others.className];
Expand All @@ -38,8 +46,21 @@ export default function Link({
if (isJump) cname.push('a-link__jump a-link__icon-after-text');
if (isJumpLeft) cname.push('a-link__jump a-link__icon-before-text');

if (isRouterLink) {
if (!href) {
throw new Error(
'Link component: href is a required attribute when isRouterLink is true'
);
}
return (
<RouterLink to={href} {...others} className={classnames(cname)}>
{children}
</RouterLink>
);
}

return (
<a {...others} className={classnames(cname)}>
<a {...others} className={classnames(cname)} href={href}>
{children}
</a>
);
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export {
LinkText,
ListLink
} from './components/Link/Link';
export type { LinkProperties } from './components/Link/Link';
export { default as List } from './components/List/List';
export {
default as ListItem,
Expand Down
7 changes: 4 additions & 3 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ export default defineConfig(() => ({
fileName: (format): string => `${name}.${format}.js`
},
rollupOptions: {
external: ['react', 'react-dom'],
external: ['react', 'react-dom', 'react-router-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
'react-dom': 'ReactDOM',
'react-router-dom': 'ReactRouterDOM'
}
}
},
optimizeDeps: {
exclude: ['react']
exclude: ['react', 'react-dom', 'react-router-dom']
},
esbuild: {
minify: true
Expand Down
Loading