Add Link component
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Link } from './Link';
|
||||
import { Flex } from '../Flex';
|
||||
import { Text } from '../Text';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Link',
|
||||
component: Link,
|
||||
args: {
|
||||
children: 'Link',
|
||||
},
|
||||
} satisfies Meta<typeof Link>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
href: 'https://canon.backstage.io',
|
||||
children: 'Sign up for Backstage',
|
||||
},
|
||||
};
|
||||
|
||||
export const AllVariants: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
},
|
||||
render: args => (
|
||||
<Flex gap="4" direction="column">
|
||||
<Link href="https://canon.backstage.io" variant="subtitle" {...args} />
|
||||
<Link href="https://canon.backstage.io" variant="body" {...args} />
|
||||
<Link href="https://canon.backstage.io" variant="caption" {...args} />
|
||||
<Link href="https://canon.backstage.io" variant="label" {...args} />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const AllWeights: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
},
|
||||
render: args => (
|
||||
<Flex gap="4" direction="column">
|
||||
<Link weight="regular" style={{ maxWidth: '600px' }} {...args} />
|
||||
<Link weight="bold" style={{ maxWidth: '600px' }} {...args} />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const Responsive: Story = {
|
||||
args: {
|
||||
variant: {
|
||||
xs: 'label',
|
||||
md: 'body',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
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} />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { forwardRef } from 'react';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import type { LinkProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
const {
|
||||
children,
|
||||
variant = 'body',
|
||||
weight = 'regular',
|
||||
style,
|
||||
className,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
// Get the responsive values for the variant and weight
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveWeight = useResponsiveValue(weight);
|
||||
|
||||
return (
|
||||
<a
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'canon-Link',
|
||||
responsiveVariant && `canon-Link--variant-${responsiveVariant}`,
|
||||
responsiveWeight && `canon-Link--weight-${responsiveWeight}`,
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
Link.displayName = 'Link';
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { Link } from './Link';
|
||||
export type { LinkProps } from './types';
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.canon-Link {
|
||||
font-family: var(--canon-font-regular);
|
||||
color: var(--canon-fg-link);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
text-decoration-line: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--canon-fg-link-hover);
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: solid;
|
||||
text-decoration-thickness: min(2px, max(1px, 0.05em));
|
||||
text-underline-offset: calc(0.025em + 2px);
|
||||
text-decoration-color: color-mix(
|
||||
in srgb,
|
||||
var(--canon-fg-link-hover) 30%,
|
||||
transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-Link--variant-body {
|
||||
font-size: var(--canon-font-size-3);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link--variant-subtitle {
|
||||
font-size: var(--canon-font-size-4);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link--variant-caption {
|
||||
font-size: var(--canon-font-size-2);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link--variant-label {
|
||||
font-size: var(--canon-font-size-1);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link--weight-regular {
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
}
|
||||
|
||||
.canon-Link--weight-bold {
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { Breakpoint } from '../../types';
|
||||
|
||||
/** @public */
|
||||
export interface LinkProps
|
||||
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
children: ReactNode;
|
||||
variant?:
|
||||
| 'subtitle'
|
||||
| 'body'
|
||||
| 'caption'
|
||||
| 'label'
|
||||
| Partial<Record<Breakpoint, 'subtitle' | 'body' | 'caption' | 'label'>>;
|
||||
weight?: 'regular' | 'bold' | Partial<Record<Breakpoint, 'regular' | 'bold'>>;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Components */
|
||||
@import '../components/Box/styles.css';
|
||||
@import '../components/Button/styles.css';
|
||||
@import '../components/Flex/styles.css';
|
||||
@@ -27,3 +26,4 @@
|
||||
@import '../components/Heading/styles.css';
|
||||
@import '../components/Input/Input.styles.css';
|
||||
@import '../components/Field/Field.styles.css';
|
||||
@import '../components/Link/styles.css';
|
||||
|
||||
Reference in New Issue
Block a user