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): allow to pass any valid <a> HTML attributes #1595

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
68 changes: 34 additions & 34 deletions src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import React from 'react';

import type {DOMProps, QAProps} from '../types';
import type {QAProps} from '../types';
import {block} from '../utils/cn';
import {eventBroker} from '../utils/event-broker';

import './Link.scss';

export type LinkView = 'normal' | 'primary' | 'secondary';

export interface LinkProps extends DOMProps, QAProps {
export interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>, QAProps {
view?: LinkView;
visitable?: boolean;
title?: string;
href: string;
target?: string;
rel?: string;
id?: string;
children?: React.ReactNode;
onClick?: React.MouseEventHandler<HTMLAnchorElement>;
onFocus?: React.FocusEventHandler<HTMLAnchorElement>;
onBlur?: React.FocusEventHandler<HTMLAnchorElement>;
/**
* @deprecated
*/
extraProps?: React.AnchorHTMLAttributes<HTMLAnchorElement>;
}

Expand All @@ -31,44 +26,49 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link
visitable,
href,
target,
rel,
title,
rel: relProp,
children,
extraProps,
onClick,
onFocus,
onBlur,
id,
style,
className,
qa,
onClickCapture,
className,
extraProps,
...restProps
},
ref,
) {
const handleClickCapture = React.useCallback((event: React.SyntheticEvent) => {
eventBroker.publish({
componentId: 'Link',
eventId: 'click',
domEvent: event,
});
}, []);
const handleClickCapture = React.useCallback(
(event: React.MouseEvent<HTMLAnchorElement>) => {
eventBroker.publish({
componentId: 'Link',
eventId: 'click',
domEvent: event,
});

if (onClickCapture) {
onClickCapture(event);
}
},
[onClickCapture],
);

const commonProps = {
title,
onClick,
onClickCapture: handleClickCapture,
onFocus,
onBlur,
id,
style,
className: b({view, visitable}, className),
'data-qa': qa,
};

const relProp = target === '_blank' && !rel ? 'noopener noreferrer' : rel;
const rel = target === '_blank' && !relProp ? 'noopener noreferrer' : relProp;

return (
<a {...extraProps} {...commonProps} ref={ref} href={href} target={target} rel={relProp}>
<a
{...commonProps}
ref={ref}
href={href}
target={target}
rel={rel}
{...restProps}
{...extraProps}
>
{children}
</a>
);
Expand Down
27 changes: 9 additions & 18 deletions src/components/Link/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,21 +167,12 @@ LANDING_BLOCK-->

## Properties

| Name | Description | Type | Default |
| :--------- | :----------------------------------------- | :-------------------------------------------------------: | :--------: |
| view | Link appearance | `"normal" \| "primary" \| "secondary"` | `"normal"` |
| visitable | Display `:visitable` CSS state | `boolean \| undefined` |
| href | HTML `href` attribute | `string` |
| target | HTML `target` attribute | `string \| undefined` |
| rel | HTML `rel` attribute | `string \| undefined` |
| title | HTML `title` attribute | `string \| undefined` |
| children | Link content | `React.ReactNode` |
| extraProps | Any additional props | `Record \| undefined` |
| onClick | `click` event handler | `React.MouseEventHandler<HTMLAnchorElement> \| undefined` |
| onFocus | `focus` event handler | `React.FocusEventHandler<HTMLAnchorElement> \| undefined` |
| onBlur | `blur` event handler | `React.FocusEventHandler<HTMLAnchorElement> \| undefined` |
| id | HTML `id` attribute | `string \| undefined` |
| style | HTML `style` attribute | `React.CSSProperties \| undefined` |
| className | HTML `class` attribute | `string \| undefined` |
| qa | HTML `data-qa` attribute, used for testing | `string \| undefined` |
| ref | React ref to Link DOM node | `React.ForwardedRef<HTMLAnchorElement> \| undefined` |
`LinkProps` extends `React.HTMLAnchorElement`.

| Name | Description | Type | Default |
| :-------- | :----------------------------------------- | :----------------------------------: | :--------: |
| children | Link content | `React.ReactNode` | |
| href | HTML `href` attribute | `string` | |
| qa | HTML `data-qa` attribute, used for testing | `string` | |
| view | Link appearance | `"normal"` `"primary"` `"secondary"` | `"normal"` |
| visitable | Display `:visitable` CSS state | `boolean` | |
63 changes: 0 additions & 63 deletions src/components/Link/__stories__/Link.new.stories.tsx

This file was deleted.

40 changes: 32 additions & 8 deletions src/components/Link/__stories__/Link.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';

import type {Meta, StoryFn} from '@storybook/react';
import type {Meta, StoryObj} from '@storybook/react';

import {Showcase} from '../../../demo/Showcase';
import {Link} from '../Link';
import type {LinkProps} from '../Link';
import {LinkShowcase} from '../__stories__/LinkShowcase';

export default {
title: 'Components/Navigation/Link',
Expand All @@ -22,10 +21,35 @@ export default {
},
},
},
} as Meta;
} as Meta<typeof Link>;

const DefaultTemplate: StoryFn<LinkProps> = (args) => <Link {...args}>Link</Link>;
export const Default = DefaultTemplate.bind({});
type Story = StoryObj<typeof Link>;

const ShowcaseTemplate: StoryFn = () => <LinkShowcase />;
export const Showcase = ShowcaseTemplate.bind({});
export const Default: Story = {args: {href: '#', children: 'Link'}};

export const View: Story = {
args: {
...Default.args,
},
render: (args) => (
<Showcase>
<Link {...args} view="normal">
Normal
</Link>
<Link {...args} view="primary">
Primary
</Link>
<Link {...args} view="secondary">
Secondary
</Link>
</Showcase>
),
};

export const Visitable = {
args: {
...Default.args,
visitable: true,
href: '.',
},
};
Loading