Skip to content

Commit 03017a8

Browse files
authored
feat(TextLink): Add color and underline styling options (#897)
* feat(TextLink): Add color and underline styling options - Introduce color prop with 'default' and 'inherit' variants - Add underline prop to control text decoration - Update CSS module with new styling classes - Extend stories and tests to cover new styling options * refactor(TextLink): Improve CSS styling for hover and child elements - Update CSS selectors to apply styles to child elements - Simplify hover state styling for color and text decoration - Ensure consistent styling across different color and underline variants * test(TextLink): Enable Chromatic snapshots for stories
1 parent 4c2240e commit 03017a8

File tree

4 files changed

+139
-22
lines changed

4 files changed

+139
-22
lines changed

src/text-link/text-link.module.css

+42-17
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,9 @@
99
font-size: inherit;
1010
font-weight: inherit;
1111
font-family: inherit;
12-
text-decoration: var(--reactist-text-link-idle-decoration);
13-
color: var(--reactist-text-link-idle-tint);
1412
cursor: pointer;
1513
}
1614

17-
.container > * {
18-
text-decoration: var(--reactist-text-link-idle-decoration);
19-
color: var(--reactist-text-link-idle-tint);
20-
}
21-
22-
/**
23-
* We need to target the child elements to ensure that styles are
24-
* applied to the text independently of the DOM elements hierarchy.
25-
*/
26-
.container:hover,
27-
.container:hover > * {
28-
text-decoration: var(--reactist-text-link-hover-decoration);
29-
color: var(--reactist-text-link-hover-tint);
30-
}
31-
3215
.container svg {
3316
display: inline-block;
3417
width: 1em;
@@ -39,3 +22,45 @@
3922
fill: currentColor;
4023
padding: 0 6px;
4124
}
25+
26+
/* Color variants */
27+
.default,
28+
.default * {
29+
color: var(--reactist-text-link-idle-tint);
30+
}
31+
32+
.default:hover,
33+
.default:hover * {
34+
color: var(--reactist-text-link-hover-tint);
35+
}
36+
37+
.inherit,
38+
.inherit * {
39+
color: inherit;
40+
}
41+
42+
.inherit:hover,
43+
.inherit:hover * {
44+
color: var(--reactist-text-link-hover-tint);
45+
}
46+
47+
/* Underline variants */
48+
.underline,
49+
.underline * {
50+
text-decoration: var(--reactist-text-link-idle-decoration);
51+
}
52+
53+
.underline:hover,
54+
.underline:hover * {
55+
text-decoration: var(--reactist-text-link-hover-decoration);
56+
}
57+
58+
.no-underline,
59+
.no-underline * {
60+
text-decoration: none;
61+
}
62+
63+
.no-underline:hover,
64+
.no-underline:hover * {
65+
text-decoration: var(--reactist-text-link-hover-decoration);
66+
}

src/text-link/text-link.stories.mdx

+25-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ A component used to create text-based hyperlinks.
1818
<Story
1919
name="Main demo"
2020
parameters={{
21-
docs: { source: { type: 'code' } },
21+
chromatic: { disableSnapshot: false },
2222
}}
2323
>
2424
<Stack space="medium" align="start">
@@ -50,7 +50,6 @@ When using nested elements inside a `TextLink`, hover styles are properly applie
5050
<Story
5151
name="Nested elements"
5252
parameters={{
53-
docs: { source: { type: 'code' } },
5453
chromatic: { disableSnapshot: false },
5554
}}
5655
>
@@ -74,3 +73,27 @@ When using nested elements inside a `TextLink`, hover styles are properly applie
7473
</Stack>
7574
</Story>
7675
</Canvas>
76+
77+
## Style
78+
79+
The `color` prop can be used to change the color of the link. The default color sets the link to color defined in `--reactist-text-link-idle-tint` and hover to `--reactist-text-link-hover-tint`. The `color` prop allows to change it to `inherit`.
80+
81+
The `underline` prop can be used to change the underline style of the link. The default is `true`.
82+
83+
<Canvas>
84+
<Story
85+
name="Colors"
86+
parameters={{
87+
chromatic: { disableSnapshot: false },
88+
}}
89+
>
90+
<Stack space="medium" align="start">
91+
<TextLink href="https://www.doist.com/" color="inherit">
92+
inherit color
93+
</TextLink>
94+
<TextLink href="https://www.doist.com/" underline={false}>
95+
no underline
96+
</TextLink>
97+
</Stack>
98+
</Story>
99+
</Canvas>

src/text-link/text-link.test.tsx

+52
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,56 @@ describe('TextLink', () => {
6262
// Verify it still has the default container class
6363
expect(link).toHaveClass('container')
6464
})
65+
66+
it('applies default color class when no color prop is provided', () => {
67+
render(<TextLink href="#">Default color</TextLink>)
68+
69+
const link = screen.getByText('Default color')
70+
expect(link).toHaveClass('default')
71+
})
72+
73+
it('applies inherit color class when color prop is set to inherit', () => {
74+
render(
75+
<TextLink href="#" color="inherit">
76+
Inherit color
77+
</TextLink>,
78+
)
79+
80+
const link = screen.getByText('Inherit color')
81+
expect(link).toHaveClass('inherit')
82+
})
83+
84+
it('applies underline class by default', () => {
85+
render(<TextLink href="#">Underlined link</TextLink>)
86+
87+
const link = screen.getByText('Underlined link')
88+
expect(link).toHaveClass('underline')
89+
})
90+
91+
it('applies no-underline class when underline prop is false', () => {
92+
render(
93+
<TextLink href="#" underline={false}>
94+
No underline
95+
</TextLink>,
96+
)
97+
98+
const link = screen.getByText('No underline')
99+
expect(link).toHaveClass('no-underline')
100+
})
101+
102+
it('combines multiple classes correctly', () => {
103+
render(
104+
<TextLink
105+
href="#"
106+
color="inherit"
107+
underline={false}
108+
exceptionallySetClassName="custom-class"
109+
>
110+
Combined classes
111+
</TextLink>,
112+
)
113+
114+
const link = screen.getByText('Combined classes')
115+
expect(link).toHaveClass('container', 'inherit', 'no-underline', 'custom-class')
116+
})
65117
})

src/text-link/text-link.tsx

+20-3
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,35 @@ import { polymorphicComponent } from '../utils/polymorphism'
44
import styles from './text-link.module.css'
55
import type { OpenInNewTab } from '../utils/common-types'
66

7-
type TextLinkProps = OpenInNewTab
7+
type TextLinkColors = 'default' | 'inherit'
8+
9+
type TextLinkProps = OpenInNewTab & {
10+
color?: TextLinkColors
11+
underline?: boolean
12+
}
813

914
const TextLink = polymorphicComponent<'a', TextLinkProps>(function TextLink(
10-
{ as = 'a', openInNewTab = false, exceptionallySetClassName, ...props },
15+
{
16+
as = 'a',
17+
openInNewTab = false,
18+
exceptionallySetClassName,
19+
color = 'default',
20+
underline = true,
21+
...props
22+
},
1123
ref,
1224
) {
1325
return (
1426
<Box
1527
{...props}
1628
as={as}
1729
display="inline"
18-
className={[exceptionallySetClassName, styles.container]}
30+
className={[
31+
exceptionallySetClassName,
32+
styles.container,
33+
styles[color],
34+
underline ? styles.underline : styles['no-underline'],
35+
]}
1936
ref={ref}
2037
target={openInNewTab ? '_blank' : undefined}
2138
rel={openInNewTab ? 'noopener noreferrer' : undefined}

0 commit comments

Comments
 (0)