fix(SW-2101): do not apply underline to Material icons inside Link and Button

This commit is contained in:
Michael Zetterberg
2025-03-31 16:36:31 +02:00
parent d513184be4
commit 35f9c3aab5
7 changed files with 78 additions and 8 deletions

View File

@@ -278,7 +278,10 @@ a.default {
.baseText:focus,
.baseText:hover {
color: var(--Base-Button-Text-On-Fill-Hover);
text-decoration: underline;
& span:not(:global(.material-symbols)) {
text-decoration: underline;
}
}
.baseText:disabled {
@@ -297,7 +300,6 @@ a.default {
.icon.baseText:focus svg *,
.icon.baseText:hover svg * {
fill: var(--Base-Button-Text-On-Fill-Hover);
text-decoration: underline;
}
.icon.baseText:disabled svg,

View File

@@ -1,14 +1,29 @@
"use client"
import { Slot } from "@radix-ui/react-slot"
import { Children, type ReactNode } from "react"
import { Button as ButtonRAC } from "react-aria-components"
import { buttonVariants } from "./variants"
import type { ButtonProps } from "./button"
// We wrap all text nodes to avoid having consumers manually wrap text nodes in spans.
// This is so that we can better support underline on buttons as Material Symbols
// are implemented as a font and therefore gets underline. Icons inside buttons
// should not get an underline.
function wrapTextNodes(children: ReactNode): ReactNode {
return Children.map(children, (child) => {
if (typeof child === "string") {
return <span>{child}</span>
}
return child
})
}
export default function Button(props: ButtonProps) {
const {
children,
className,
clean,
intent,
@@ -31,9 +46,17 @@ export default function Button(props: ButtonProps) {
variant,
})
const wrappedChildren =
typeof children === "function" ? children : wrapTextNodes(children)
if (restProps.asChild) {
const { asChild, ...slotProps } = restProps
return <Slot className={classNames} {...slotProps} />
return (
<Slot className={classNames} {...slotProps}>
{/* @ts-expect-error: Incorrect types for Slot */}
{wrappedChildren}
</Slot>
)
}
const { asChild, onClick, disabled, ...racProps } = restProps
@@ -43,6 +66,8 @@ export default function Button(props: ButtonProps) {
isDisabled={disabled}
onPress={onClick}
{...racProps}
/>
>
{wrappedChildren}
</ButtonRAC>
)
}

View File

@@ -1,7 +1,7 @@
"use client"
import NextLink from "next/link"
import { usePathname, useSearchParams } from "next/navigation"
import { useCallback, useMemo } from "react"
import { Children, type ReactNode, useCallback, useMemo } from "react"
import { useCheckIfExternalLink } from "@/hooks/useCheckIfExternalLink"
import { trackClick } from "@/utils/tracking"
@@ -10,7 +10,21 @@ import { linkVariants } from "./variants"
import type { LinkProps } from "./link"
// We wrap all text nodes to avoid having consumers manually wrap text nodes in spans.
// This is so that we can better support underline on links as Material Symbols
// are implemented as a font and therefore gets underline. Icons inside links
// should not get an underline.
function wrapTextNodes(children: ReactNode): ReactNode {
return Children.map(children, (child) => {
if (typeof child === "string") {
return <span>{child}</span>
}
return child
})
}
export default function Link({
children,
active,
className,
color,
@@ -96,6 +110,9 @@ export default function Link({
className: classNames,
}
const wrappedChildren =
typeof children === "function" ? children : wrapTextNodes(children)
return isExternal ? (
<a
{...linkProps}
@@ -105,7 +122,9 @@ export default function Link({
onClick(e)
}
}}
/>
>
{wrappedChildren}
</a>
) : (
<NextLink
scroll={scroll}
@@ -121,6 +140,8 @@ export default function Link({
id={trackingId}
{...props}
{...linkProps}
/>
>
{wrappedChildren}
</NextLink>
)
}

View File

@@ -43,7 +43,10 @@
font-weight: var(--typography-Body-Underline-fontWeight);
letter-spacing: var(--typography-Body-Underline-letterSpacing);
line-height: var(--typography-Body-Underline-lineHeight);
text-decoration: underline;
& span:not(:global(.material-symbols)) {
text-decoration: underline;
}
}
.myPageMobileDropdown {