Skip to content

Commit 8a49db2

Browse files
authored
Fix underline size on Link component when arrowDirection='none' (#887)
* fix bug where Link underline doesn't take full width when there's no arrow * add changeset * refactored Link stories * update snapshots * add new exports to changeset
1 parent 75f0413 commit 8a49db2

11 files changed

+87
-41
lines changed

.changeset/curly-guests-sell.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@primer/react-brand': patch
3+
---
4+
5+
`Link` component improvements.
6+
7+
- Fixed a bug in the `Link` component where the underline wouldn't take the full width when `arrowDirection='none'`.
8+
- Prop options are also now exported from the package root, specifically:
9+
- `LinkSizes`
10+
- `LinkArrowDirections`
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,37 @@
1-
import React from 'react'
2-
import {Meta, StoryFn} from '@storybook/react'
3-
import {Link} from '.'
1+
import type {Meta, StoryObj} from '@storybook/react'
42

5-
const meta: Meta<typeof Link> = {
6-
title: 'Components/Link/features',
7-
component: Link,
8-
}
3+
import {type LinkProps} from '.'
4+
import baseMeta from './Link.stories'
95

6+
const meta: Meta<LinkProps> = {...baseMeta, title: 'Components/Link/Features'}
107
export default meta
118

12-
const Template: StoryFn<typeof Link> = args => <Link {...args} />
9+
type Story = StoryObj<LinkProps>
10+
11+
export const Large: Story = {
12+
args: {
13+
size: 'large',
14+
href: '#',
15+
children: 'Large size',
16+
},
17+
}
1318

14-
export const Large = Template.bind({})
15-
Large.args = {
16-
size: 'large',
17-
href: '#',
18-
children: 'Large size',
19+
export const ArrowStart: Story = {
20+
args: {
21+
children: 'Back to schedule',
22+
arrowDirection: 'start',
23+
},
1924
}
2025

21-
export const Reversed = Template.bind({})
22-
Reversed.args = {
23-
size: 'medium',
24-
href: '#',
25-
children: 'Back to schedule',
26-
arrowDirection: 'start',
26+
export const NoArrow: Story = {
27+
args: {
28+
arrowDirection: 'none',
29+
},
2730
}
2831

29-
export const Accent = Template.bind({})
30-
Accent.args = {
31-
size: 'medium',
32-
variant: 'accent',
33-
href: '#',
34-
children: 'Accent color',
32+
export const Accent: Story = {
33+
args: {
34+
variant: 'accent',
35+
children: 'Accent variant',
36+
},
3537
}

packages/react/src/Link/Link.module.css

+4
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,7 @@
7878
margin-left: auto;
7979
margin-right: 4px;
8080
}
81+
82+
.Link.Link--arrow-none::after {
83+
width: 100%;
84+
}

packages/react/src/Link/Link.module.css.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ declare const styles: {
66
readonly "Link-arrow": string;
77
readonly "Link--large": string;
88
readonly "Link--arrow-start": string;
9+
readonly "Link--arrow-none": string;
910
};
1011
export = styles;
1112

+32-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
1-
import React from 'react'
2-
import {Meta, StoryFn} from '@storybook/react'
3-
import {Link} from '.'
1+
import type {Meta, StoryObj} from '@storybook/react'
42

5-
export default {
3+
import {Link, LinkArrowDirections, LinkSizes, LinkVariants, type LinkProps} from '.'
4+
5+
const meta: Meta<LinkProps> = {
66
title: 'Components/Link',
77
component: Link,
8-
} as Meta<typeof Link>
8+
args: {
9+
children: 'Learn more',
10+
size: 'medium',
11+
arrowDirection: 'end',
12+
variant: 'default',
13+
},
14+
argTypes: {
15+
children: {
16+
control: 'text',
17+
},
18+
arrowDirection: {
19+
options: LinkArrowDirections,
20+
control: {type: 'inline-radio'},
21+
},
22+
size: {
23+
options: LinkSizes,
24+
control: {type: 'inline-radio'},
25+
},
26+
variant: {
27+
options: LinkVariants,
28+
control: {type: 'inline-radio'},
29+
},
30+
},
31+
}
932

10-
const Template: StoryFn<typeof Link> = args => <Link {...args} />
33+
export default meta
1134

12-
export const Default = Template.bind({})
13-
Default.args = {
14-
// size: 'medium',
15-
href: '#',
16-
children: 'Primary action',
17-
}
35+
type Story = StoryObj<LinkProps>
36+
37+
export const Default: Story = {}

packages/react/src/Link/Link.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@ import styles from './Link.module.css'
77
import '@primer/brand-primitives/lib/design-tokens/css/tokens/functional/components/link/colors-with-modes.css'
88

99
export const LinkVariants = ['default', 'accent'] as const
10+
export const LinkSizes = ['medium', 'large'] as const
11+
export const LinkArrowDirections = ['start', 'end', 'none'] as const
1012

1113
export type LinkProps = {
1214
/**
1315
* The size variations available in Link
1416
*/
15-
size?: 'medium' | 'large'
17+
size?: (typeof LinkSizes)[number]
1618
/**
1719
* Position of the arrow.
1820
*/
19-
arrowDirection?: 'start' | 'end' | 'none'
21+
arrowDirection?: (typeof LinkArrowDirections)[number]
2022
/**
2123
* Specify alternative link appearance
2224
*/

packages/react/src/Link/Link.visual.spec.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ test.describe('Visual Comparison: Link', () => {
2121
expect(await page.screenshot({fullPage: true})).toMatchSnapshot()
2222
})
2323

24-
test('Link / Reversed', async ({page}) => {
25-
await page.goto('http://localhost:6006/iframe.html?args=&id=components-link-features--reversed&viewMode=story')
24+
test('Link / Arrow Start', async ({page}) => {
25+
await page.goto('http://localhost:6006/iframe.html?args=&id=components-link-features--arrow-start&viewMode=story')
26+
27+
await page.waitForTimeout(500)
28+
expect(await page.screenshot({fullPage: true})).toMatchSnapshot()
29+
})
30+
31+
test('Link / No Arrow', async ({page}) => {
32+
await page.goto('http://localhost:6006/iframe.html?args=&id=components-link-features--no-arrow&viewMode=story')
2633

2734
await page.waitForTimeout(500)
2835
expect(await page.screenshot({fullPage: true})).toMatchSnapshot()

0 commit comments

Comments
 (0)