summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOliver <oliver@mohlin.dev>2025-05-26 13:35:22 +0200
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-05-27 21:33:16 +0200
commit03a8ec21927cbcb9ef8bb5c855bddafff3c4af47 (patch)
tree81cfbe810c40c57fc8c28c05c0ee54f9fe6a72b7
parentc758efedaabd146b7ee0aa5b272d72bc1a72a2e5 (diff)
downloadmullvadvpn-03a8ec21927cbcb9ef8bb5c855bddafff3c4af47.tar.xz
mullvadvpn-03a8ec21927cbcb9ef8bb5c855bddafff3c4af47.zip
Refactor Link to better handle icon alignment
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/link/Link.tsx94
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/link/components/LinkIcon.tsx5
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/link/index.ts1
3 files changed, 53 insertions, 47 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/Link.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/Link.tsx
index 40a598b666..5e1bef8d5f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/Link.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/Link.tsx
@@ -1,62 +1,66 @@
import React from 'react';
-import styled from 'styled-components';
+import styled, { css } from 'styled-components';
-import { Colors, colors, Radius } from '../../foundations';
-import { Text, TextProps } from '../typography';
-import { LinkIcon } from './components';
+import { Colors, colors, Radius, Typography } from '../../foundations';
+import { TransientProps } from '../../types';
+import { LinkIcon, LinkText, StyledIcon as StyledLinkIcon, StyledLinkText } from './components';
+import { useHoverColor } from './hooks';
+import { LinkProvider } from './LinkContext';
-export type LinkProps<T extends React.ElementType = 'a'> = TextProps<T> & {
+type LinkBaseProps = {
+ variant?: Typography;
+ color?: Colors;
onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
};
-const StyledText = styled(Text)<{
- $hoverColor: Colors | undefined;
-}>((props) => ({
- background: colors.transparent,
- cursor: 'default',
- textDecoration: 'none',
- display: 'inline',
+export type LinkProps = LinkBaseProps &
+ Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkBaseProps>;
- '&&:hover': {
- textDecorationLine: 'underline',
- textUnderlineOffset: '2px',
- color: props.$hoverColor,
- },
- '&&:focus-visible': {
- borderRadius: Radius.radius4,
- outline: `2px solid ${colors.whiteAlpha60}`,
- outlineOffset: '2px',
- },
-}));
-
-const getHoverColor = (color: Colors | undefined) => {
- switch (color) {
- case 'whiteAlpha60':
- return 'white';
- default:
- return undefined;
+const StyledLink = styled.a<
+ TransientProps<LinkProps> & {
+ $hoverColor?: Colors;
}
-};
+>(({ $hoverColor }) => {
+ return css`
+ cursor: default;
+ text-decoration: none;
+ display: inline;
+ width: fit-content;
+
+ &&:hover > ${StyledLinkText} {
+ text-decoration-line: underline;
+ text-underline-offset: 2px;
+ color: ${$hoverColor};
+ }
+
+ &&:focus-visible > ${StyledLinkText} {
+ border-radius: ${Radius.radius4};
+ outline: 2px solid ${colors.white};
+ outline-offset: 2px;
+ }
+
+ > ${StyledLinkIcon}:first-child:not(:only-child) {
+ margin-right: 2px;
+ }
+ > ${StyledLinkIcon}:last-child:not(:only-child) {
+ margin-left: 2px;
+ }
+ `;
+});
-function Link<T extends React.ElementType = 'a'>({
- as: forwardedAs,
- color,
- ...props
-}: LinkProps<T>) {
- // If `as` is provided we need to pass it as `forwardedAs` for it to
- // be correctly passed to the `Text` component.
- const componentProps = forwardedAs ? { ...props, forwardedAs } : props;
+function Link({ color, variant, children, ...props }: LinkProps) {
+ const hoverColor = useHoverColor(color);
return (
- <StyledText
- forwardedAs="a"
- color={color}
- $hoverColor={getHoverColor(color)}
- {...componentProps}
- />
+ <LinkProvider variant={variant} color={color}>
+ <StyledLink $hoverColor={hoverColor} {...props}>
+ {children}
+ </StyledLink>
+ </LinkProvider>
);
}
const LinkNamespace = Object.assign(Link, {
+ Text: LinkText,
Icon: LinkIcon,
});
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/components/LinkIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/components/LinkIcon.tsx
index 7af4b28045..3a82f11a4d 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/components/LinkIcon.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/components/LinkIcon.tsx
@@ -5,8 +5,9 @@ import { Icon, IconProps } from '../../icon';
type LinkIconProps = IconProps;
export const StyledIcon = styled(Icon)`
- vertical-align: middle;
- display: inline-flex;
+ vertical-align: text-bottom;
+ display: inline-block;
+ flex-shrink: 0;
`;
export function LinkIcon({ ...props }: LinkIconProps) {
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/index.ts
new file mode 100644
index 0000000000..3db78f51f0
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/link/index.ts
@@ -0,0 +1 @@
+export * from './Link';