First pass at moving Link to React Aria
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -18,7 +18,6 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Link } from './Link';
|
||||
import { Flex } from '../Flex';
|
||||
import { Text } from '../Text';
|
||||
import { Link as RouterLink, MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Link',
|
||||
@@ -33,7 +32,7 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
to: 'https://ui.backstage.io',
|
||||
href: 'https://ui.backstage.io',
|
||||
children: 'Sign up for Backstage',
|
||||
},
|
||||
};
|
||||
@@ -44,10 +43,14 @@ export const AllVariants: Story = {
|
||||
},
|
||||
render: args => (
|
||||
<Flex gap="4" direction="column">
|
||||
<Link href="https://ui.backstage.io" variant="subtitle" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="body" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="caption" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="label" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="title-large" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="title-medium" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="title-small" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="title-x-small" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="body-large" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="body-medium" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="body-small" {...args} />
|
||||
<Link href="https://ui.backstage.io" variant="body-x-small" {...args} />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
@@ -58,8 +61,102 @@ export const AllWeights: Story = {
|
||||
},
|
||||
render: args => (
|
||||
<Flex gap="4" direction="column">
|
||||
<Link weight="regular" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Link weight="bold" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-large"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-large"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-medium"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-medium"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-small"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-small"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-x-small"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="title-x-small"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-large"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-large"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-medium"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-medium"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-small"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-small"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-x-small"
|
||||
weight="regular"
|
||||
{...args}
|
||||
/>
|
||||
<Link
|
||||
href="https://ui.backstage.io"
|
||||
variant="body-x-small"
|
||||
weight="bold"
|
||||
{...args}
|
||||
/>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
@@ -68,43 +165,32 @@ export const Responsive: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
variant: {
|
||||
xs: 'label',
|
||||
md: 'body',
|
||||
xs: 'title-x-small',
|
||||
md: 'body-x-small',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomRender: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<Flex gap="4" direction="column" align="start">
|
||||
<Link render={<RouterLink to="/catalog" />}>Go to Catalog</Link>
|
||||
</Flex>
|
||||
);
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<MemoryRouter>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export const Playground: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
},
|
||||
render: args => (
|
||||
<Flex gap="4" direction="column">
|
||||
<Text>Subtitle</Text>
|
||||
<Link variant="subtitle" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Body</Text>
|
||||
<Link variant="body" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Caption</Text>
|
||||
<Link variant="caption" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Label</Text>
|
||||
<Link variant="label" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Title X Small</Text>
|
||||
<Link variant="title-x-small" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Body X Small</Text>
|
||||
<Link variant="body-x-small" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Body Small</Text>
|
||||
<Link variant="body-small" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Body Medium</Text>
|
||||
<Link variant="body-medium" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Body Large</Text>
|
||||
<Link variant="body-large" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Title Small</Text>
|
||||
<Link variant="title-small" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Text>Title Medium</Text>
|
||||
<Link variant="title-medium" style={{ maxWidth: '600px' }} {...args} />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -14,37 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useRef, forwardRef } from 'react';
|
||||
import { useRender } from '@base-ui-components/react/use-render';
|
||||
import { forwardRef } from 'react';
|
||||
import { Link as AriaLink } from 'react-aria-components';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
import type { LinkProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const Link = forwardRef<HTMLElement, LinkProps>((props, ref) => {
|
||||
export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
const {
|
||||
className,
|
||||
variant = 'body',
|
||||
weight = 'regular',
|
||||
render = <a />,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const { classNames, dataAttributes } = useStyles('Link', { variant, weight });
|
||||
const internalRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
const { renderElement } = useRender({
|
||||
render,
|
||||
props: {
|
||||
className: clsx(classNames.root, className),
|
||||
...dataAttributes,
|
||||
...restProps,
|
||||
},
|
||||
refs: [ref, internalRef],
|
||||
});
|
||||
|
||||
return renderElement();
|
||||
return (
|
||||
<AriaLink
|
||||
ref={ref}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...dataAttributes}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Link.displayName = 'Link';
|
||||
|
||||
@@ -36,22 +36,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='body'] {
|
||||
font-size: var(--bui-font-size-3);
|
||||
.bui-Link[data-variant='title-large'] {
|
||||
font-size: var(--bui-font-size-8);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='subtitle'] {
|
||||
.bui-Link[data-variant='title-medium'] {
|
||||
font-size: var(--bui-font-size-7);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='title-small'] {
|
||||
font-size: var(--bui-font-size-6);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='title-x-small'] {
|
||||
font-size: var(--bui-font-size-5);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='body-large'] {
|
||||
font-size: var(--bui-font-size-4);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='caption'] {
|
||||
.bui-Link[data-variant='body-medium'] {
|
||||
font-size: var(--bui-font-size-3);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='body-small'] {
|
||||
font-size: var(--bui-font-size-2);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.bui-Link[data-variant='label'] {
|
||||
.bui-Link[data-variant='body-x-small'] {
|
||||
font-size: var(--bui-font-size-1);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
@@ -14,21 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { Breakpoint } from '../../types';
|
||||
import type { useRender } from '@base-ui-components/react/use-render';
|
||||
import type { LinkProps as AriaLinkProps } from 'react-aria-components';
|
||||
|
||||
/** @public */
|
||||
export interface LinkProps extends useRender.ComponentProps<'a'> {
|
||||
children: ReactNode;
|
||||
to?: string;
|
||||
export interface LinkProps extends AriaLinkProps {
|
||||
variant?:
|
||||
| 'subtitle'
|
||||
| 'body'
|
||||
| 'caption'
|
||||
| 'label'
|
||||
| Partial<Record<Breakpoint, 'subtitle' | 'body' | 'caption' | 'label'>>;
|
||||
| 'title-large'
|
||||
| 'title-medium'
|
||||
| 'title-small'
|
||||
| 'title-x-small'
|
||||
| 'body-large'
|
||||
| 'body-medium'
|
||||
| 'body-small'
|
||||
| 'body-x-small'
|
||||
| Partial<
|
||||
Record<
|
||||
Breakpoint,
|
||||
| 'title-large'
|
||||
| 'title-medium'
|
||||
| 'title-small'
|
||||
| 'title-x-small'
|
||||
| 'body-large'
|
||||
| 'body-medium'
|
||||
| 'body-small'
|
||||
| 'body-x-small'
|
||||
>
|
||||
>;
|
||||
weight?: 'regular' | 'bold' | Partial<Record<Breakpoint, 'regular' | 'bold'>>;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user