summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2025-03-18 21:32:50 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2025-03-18 21:32:50 +0100
commit793c39338a2fcd2bf188952061edaeaa925d614a (patch)
tree9d2d643af5271ff756eb645bbd99c2cf561858f8
parente145159131c1b750d3b3f4c7bba7d44278191f94 (diff)
parent8bc21e0298d121bef5836d6f788be5436dffc2d3 (diff)
downloadmullvadvpn-793c39338a2fcd2bf188952061edaeaa925d614a.tar.xz
mullvadvpn-793c39338a2fcd2bf188952061edaeaa925d614a.zip
Merge branch 'add-support-for-external-links-in-link-component-des-1826'
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ExternalLink.tsx24
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/InternalLink.tsx24
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx5
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/navigation-header/components/NavigationHeaderTitle.tsx4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmall.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmallSemiBold.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/FootnoteMini.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Label.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/LabelTiny.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx47
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Text.tsx77
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleBig.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleLarge.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleMedium.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts2
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/types/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/types/polymorphic-props.ts4
-rw-r--r--desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts6
22 files changed, 154 insertions, 142 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ExternalLink.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ExternalLink.tsx
new file mode 100644
index 0000000000..6ef57cc4eb
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ExternalLink.tsx
@@ -0,0 +1,24 @@
+import { useCallback } from 'react';
+
+import { Url } from '../../shared/constants';
+import { useAppContext } from '../context';
+import { Link, LinkProps } from '../lib/components';
+
+export type ExternalLinkProps = Omit<LinkProps<'a'>, 'href' | 'as'> & {
+ to: Url;
+};
+
+export const ExternalLink = ({ to, onClick, ...props }: ExternalLinkProps) => {
+ const { openUrl } = useAppContext();
+ const navigate = useCallback(
+ (e: React.MouseEvent<HTMLAnchorElement>) => {
+ e.preventDefault();
+ if (onClick) {
+ onClick(e);
+ }
+ return openUrl(to);
+ },
+ [onClick, openUrl, to],
+ );
+ return <Link href="" onClick={navigate} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/InternalLink.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/InternalLink.tsx
new file mode 100644
index 0000000000..6b45d99fee
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/InternalLink.tsx
@@ -0,0 +1,24 @@
+import { useCallback } from 'react';
+
+import { Link, LinkProps } from '../lib/components';
+import { useHistory } from '../lib/history';
+import { RoutePath } from '../lib/routes';
+
+export type InternalLinkProps = Omit<LinkProps<'a'>, 'href' | 'as'> & {
+ to: RoutePath;
+};
+
+export const InternalLink = ({ to, onClick, ...props }: InternalLinkProps) => {
+ const history = useHistory();
+ const navigate = useCallback(
+ (e: React.MouseEvent<HTMLAnchorElement>) => {
+ e.preventDefault();
+ if (onClick) {
+ onClick(e);
+ }
+ return history.push(to);
+ },
+ [history, to, onClick],
+ );
+ return <Link href="" onClick={navigate} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx
index d9c6cbb666..b0588e6c0d 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx
@@ -16,7 +16,6 @@ import {
} from '../../shared/notifications';
import { useAppContext } from '../context';
import useActions from '../lib/actionsHook';
-import { Link } from '../lib/components';
import { Colors } from '../lib/foundations';
import { transitions, useHistory } from '../lib/history';
import { formatHtml } from '../lib/html-formatter';
@@ -28,6 +27,7 @@ import { RoutePath } from '../lib/routes';
import accountActions from '../redux/account/actions';
import { IReduxState, useSelector } from '../redux/store';
import * as AppButton from './AppButton';
+import { InternalLink } from './InternalLink';
import { ModalAlert, ModalAlertType, ModalMessage, ModalMessageList } from './Modal';
import {
NotificationActions,
@@ -141,13 +141,13 @@ export default function NotificationArea(props: IProps) {
{notification.title}
</NotificationTitle>
<NotificationSubtitle data-testid="notificationSubTitle">
- {notification.subtitleAction?.type === 'navigate' ? (
- <Link
+ {notification.subtitleAction?.type === 'navigate-internal' ? (
+ <InternalLink
variant="labelTiny"
color={Colors.white60}
{...notification.subtitleAction.link}>
{formatHtml(notification.subtitle ?? '')}
- </Link>
+ </InternalLink>
) : (
formatHtml(notification.subtitle ?? '')
)}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx
index de117fccb2..a1a3c02b3a 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx
@@ -1,13 +1,14 @@
+import React from 'react';
import styled from 'styled-components';
import { Colors } from '../../../foundations';
import { BodySmallSemiBold, BodySmallSemiBoldProps } from '../../typography';
import { useButtonContext } from '../ButtonContext';
-export type ButtonTextProps = Omit<BodySmallSemiBoldProps, 'color'>;
+export type ButtonTextProps<T extends React.ElementType = 'span'> = BodySmallSemiBoldProps<T>;
export const StyledText = styled(BodySmallSemiBold)``;
-export const ButtonText = (props: ButtonTextProps) => {
+export const ButtonText = <T extends React.ElementType = 'span'>(props: ButtonTextProps<T>) => {
const { disabled } = useButtonContext();
return <StyledText color={disabled ? Colors.white40 : Colors.white} {...props} />;
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx
index b79446de1f..67e3952825 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx
@@ -4,11 +4,13 @@ import { Colors } from '../../../foundations';
import { BodySmallSemiBoldProps, LabelTiny } from '../../typography';
import { useFilterChipContext } from '../FilterChipContext';
-export type FilterChipTextProps = Omit<BodySmallSemiBoldProps, 'color'>;
+export type FilterChipTextProps<T extends React.ElementType = 'span'> = BodySmallSemiBoldProps<T>;
export const StyledText = styled(LabelTiny)``;
-export const FilterChipText = (props: FilterChipTextProps) => {
+export const FilterChipText = <T extends React.ElementType = 'span'>(
+ props: FilterChipTextProps<T>,
+) => {
const { disabled } = useFilterChipContext();
return <StyledText color={disabled ? Colors.white40 : Colors.white} {...props} />;
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/navigation-header/components/NavigationHeaderTitle.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/navigation-header/components/NavigationHeaderTitle.tsx
index 7d50dacfb4..7559416c16 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/navigation-header/components/NavigationHeaderTitle.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/navigation-header/components/NavigationHeaderTitle.tsx
@@ -15,10 +15,10 @@ export const StyledText = styled(TitleMedium)<{ $visible?: boolean }>(({ $visibl
textOverflow: 'ellipsis',
}));
-export const NavigationHeaderTitle = ({ children }: NavigationHeaderTitleProps) => {
+export const NavigationHeaderTitle = ({ children, ...props }: NavigationHeaderTitleProps) => {
const { titleVisible } = useNavigationHeader();
return (
- <StyledText tag="h1" $visible={titleVisible}>
+ <StyledText forwardedAs="h1" $visible={titleVisible} {...props}>
{children}
</StyledText>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx
index b6ea92cf28..73fb6e16d5 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx
@@ -4,13 +4,15 @@ import { Colors } from '../../../foundations';
import { LabelTiny, LabelTinyProps } from '../../typography';
import { useProgress } from '../ProgressContext';
-export type ProgressPercentProps = Omit<LabelTinyProps, 'children'>;
+export type ProgressPercentProps<T extends React.ElementType = 'span'> = LabelTinyProps<T>;
const StyledText = styled(LabelTiny)`
min-width: 26px;
`;
-export const ProgressPercent = (props: ProgressPercentProps) => {
+export const ProgressPercent = <T extends React.ElementType = 'span'>(
+ props: ProgressPercentProps<T>,
+) => {
const { percent, disabled } = useProgress();
return (
<StyledText color={disabled ? Colors.white40 : Colors.white} {...props}>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx
index 36ad555eec..b5663bd4c7 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx
@@ -2,13 +2,9 @@ import { Colors } from '../../../foundations';
import { LabelTiny, LabelTinyProps } from '../../typography';
import { useProgress } from '../ProgressContext';
-export type ProgressTextProps = LabelTinyProps;
+export type ProgressTextProps<T extends React.ElementType = 'span'> = LabelTinyProps<T>;
-export const ProgressText = ({ children, ...props }: ProgressTextProps) => {
+export const ProgressText = <T extends React.ElementType = 'span'>(props: ProgressTextProps<T>) => {
const { disabled } = useProgress();
- return (
- <LabelTiny color={disabled ? Colors.white40 : Colors.white60} {...props}>
- {children}
- </LabelTiny>
- );
+ return <LabelTiny color={disabled ? Colors.white40 : Colors.white60} {...props} />;
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmall.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmall.tsx
index 18ab10e202..b68da08c18 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmall.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmall.tsx
@@ -1,9 +1,7 @@
import { Text, TextProps } from './Text';
-export type BodySmallProps = Omit<TextProps, 'variant'>;
+export type BodySmallProps<E extends React.ElementType = 'span'> = TextProps<E>;
-export const BodySmall = ({ children, ...props }: BodySmallProps) => (
- <Text variant="bodySmall" {...props}>
- {children}
- </Text>
+export const BodySmall = <T extends React.ElementType = 'span'>(props: BodySmallProps<T>) => (
+ <Text variant="bodySmall" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmallSemiBold.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmallSemiBold.tsx
index f70a2c7b11..402153fa6c 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmallSemiBold.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/BodySmallSemiBold.tsx
@@ -1,9 +1,7 @@
import { Text, TextProps } from './Text';
-export type BodySmallSemiBoldProps = Omit<TextProps, 'variant'>;
+export type BodySmallSemiBoldProps<E extends React.ElementType = 'span'> = TextProps<E>;
-export const BodySmallSemiBold = ({ children, ...props }: BodySmallSemiBoldProps) => (
- <Text variant="bodySmallSemibold" {...props}>
- {children}
- </Text>
-);
+export const BodySmallSemiBold = <T extends React.ElementType = 'span'>(
+ props: BodySmallSemiBoldProps<T>,
+) => <Text variant="bodySmallSemibold" {...props} />;
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/FootnoteMini.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/FootnoteMini.tsx
index 77d563e03c..75a6ac3d39 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/FootnoteMini.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/FootnoteMini.tsx
@@ -1,9 +1,7 @@
import { Text, TextProps } from './Text';
-export type FoonoteMiniProps = Omit<TextProps, 'variant'>;
+export type FootnoteMiniProps<E extends React.ElementType = 'span'> = TextProps<E>;
-export const FootnoteMini = ({ children, ...props }: FoonoteMiniProps) => (
- <Text variant="footnoteMini" {...props}>
- {children}
- </Text>
+export const FootnoteMini = <T extends React.ElementType = 'span'>(props: FootnoteMiniProps<T>) => (
+ <Text variant="footnoteMini" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Label.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Label.tsx
index d3ae088dff..9bb7dc7b03 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Label.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Label.tsx
@@ -1,12 +1,8 @@
import { Text } from './Text';
import { TextProps } from './Text';
-export type LabelProps = TextProps & React.LabelHTMLAttributes<HTMLLabelElement>;
+export type LabelProps<T extends React.ElementType = 'label'> = TextProps<T>;
-export const Label = ({ children, ...props }: LabelProps) => {
- return (
- <Text as={'label'} {...props}>
- {children}
- </Text>
- );
+export const Label = <T extends React.ElementType = 'label'>(props: LabelProps<T>) => {
+ return <Text as="label" {...props} />;
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/LabelTiny.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/LabelTiny.tsx
index f7a952e67e..c8dc9865cc 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/LabelTiny.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/LabelTiny.tsx
@@ -1,8 +1,7 @@
import { Text, TextProps } from './Text';
-export type LabelTinyProps = Omit<TextProps, 'variant'>;
-export const LabelTiny = ({ children, ...props }: LabelTinyProps) => (
- <Text variant="labelTiny" {...props}>
- {children}
- </Text>
+export type LabelTinyProps<E extends React.ElementType = 'span'> = TextProps<E>;
+
+export const LabelTiny = <T extends React.ElementType = 'span'>(props: LabelTinyProps<T>) => (
+ <Text variant="labelTiny" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx
index e3c8673a54..eb1d75917c 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx
@@ -1,28 +1,28 @@
-import React, { useCallback } from 'react';
+import React from 'react';
import styled from 'styled-components';
import { Colors, Radius } from '../../foundations';
-import { useHistory } from '../../history';
-import { RoutePath } from '../../routes';
-import { buttonReset } from '../../styles';
import { Text, TextProps } from './Text';
-export interface LinkProps extends TextProps, Omit<React.HtmlHTMLAttributes<'button'>, 'color'> {
- to: RoutePath;
-}
+export type LinkProps<T extends React.ElementType = 'a'> = TextProps<T> & {
+ onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
+};
const StyledText = styled(Text)<{
$hoverColor: Colors | undefined;
}>((props) => ({
- ...buttonReset,
background: 'transparent',
+ cursor: 'default',
+ textDecoration: 'none',
+ display: 'inline-flex',
+ alignItems: 'center',
- '&:hover': {
+ '&&:hover': {
textDecorationLine: 'underline',
textUnderlineOffset: '2px',
color: props.$hoverColor,
},
- '&:focus-visible': {
+ '&&:focus-visible': {
borderRadius: Radius.radius4,
outline: `2px solid ${Colors.white}`,
outlineOffset: '2px',
@@ -38,25 +38,20 @@ const getHoverColor = (color: Colors | undefined) => {
}
};
-export const Link = ({ to, children, color, onClick, ...props }: LinkProps) => {
- const history = useHistory();
- const navigate = useCallback(
- (e: React.MouseEvent<'button'>) => {
- if (onClick) {
- onClick(e);
- }
- return history.push(to);
- },
- [history, to, onClick],
- );
+export const 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;
return (
<StyledText
- onClick={navigate}
- as={'button'}
+ forwardedAs="a"
color={color}
$hoverColor={getHoverColor(color)}
- {...props}>
- {children}
- </StyledText>
+ {...componentProps}
+ />
);
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Text.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Text.tsx
index 15a964065d..cf42893f1f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Text.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Text.tsx
@@ -1,60 +1,37 @@
-import { createElement, forwardRef } from 'react';
-import styled, { WebTarget } from 'styled-components';
+import React from 'react';
+import styled from 'styled-components';
-import { Colors, Typography, typography, TypographyProperties } from '../../foundations';
-import { TransientProps } from '../../types';
+import { Colors, Typography, typography } from '../../foundations';
+import { PolymorphicProps, TransientProps } from '../../types';
-export type TextProps = React.PropsWithChildren<{
+type TextBaseProps = {
variant?: Typography;
color?: Colors;
- tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';
- as?: WebTarget;
- style?: React.CSSProperties;
-}>;
+};
-const StyledText = styled(
- ({ tag = 'span', ...props }: { tag: TextProps['tag'] } & TransientProps<TypographyProperties>) =>
- createElement(tag, props),
-)((props) => ({
- color: 'var(--color)',
- fontFamily: props.$fontFamily,
- fontWeight: props.$fontWeight,
- fontSize: props.$fontSize,
- lineHeight: props.$lineHeight,
-}));
+export type TextProps<T extends React.ElementType = 'span'> = PolymorphicProps<T, TextBaseProps>;
-export const Text = forwardRef(
- (
- {
- tag = 'span',
- variant = 'bodySmall',
- color = Colors.white,
- children,
- style,
- ...props
- }: TextProps,
- ref,
- ) => {
- const { fontFamily, fontSize, fontWeight, lineHeight } = typography[variant];
- return (
- <StyledText
- ref={ref}
- tag={tag}
- style={
- {
- '--color': color,
- ...style,
- } as React.CSSProperties
- }
- $fontFamily={fontFamily}
- $fontWeight={fontWeight}
- $fontSize={fontSize}
- $lineHeight={lineHeight}
- {...props}>
- {children}
- </StyledText>
- );
+const StyledText = styled.span<TransientProps<TextBaseProps>>(
+ ({ $variant = 'bodySmall', $color = Colors.white }) => {
+ const { fontFamily, fontSize, fontWeight, lineHeight } = typography[$variant];
+ return `
+ --color: ${$color};
+
+ color: var(--color);
+ font-family: ${fontFamily};
+ font-size: ${fontSize};
+ font-weight: ${fontWeight};
+ line-height: ${lineHeight};
+ `;
},
);
+export const Text = <T extends React.ElementType = 'span'>({
+ variant,
+ color,
+ ...props
+}: TextProps<T>) => {
+ return <StyledText $variant={variant} $color={color} {...props} />;
+};
+
Text.displayName = 'Text';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleBig.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleBig.tsx
index 4b3b1d84ef..8060af731e 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleBig.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleBig.tsx
@@ -1,8 +1,7 @@
import { Text, TextProps } from './Text';
-export type TitleBigProps = Omit<TextProps, 'variant'>;
-export const TitleBig = ({ children, ...props }: TitleBigProps) => (
- <Text variant="titleBig" {...props}>
- {children}
- </Text>
+export type TitleBigProps<E extends React.ElementType = 'span'> = TextProps<E>;
+
+export const TitleBig = <T extends React.ElementType = 'span'>(props: TitleBigProps<T>) => (
+ <Text variant="titleBig" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleLarge.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleLarge.tsx
index c80814362e..d133bf3083 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleLarge.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleLarge.tsx
@@ -1,8 +1,7 @@
import { Text, TextProps } from './Text';
-export type TitleLargeProps = Omit<TextProps, 'variant'>;
-export const TitleLarge = ({ children, ...props }: TitleLargeProps) => (
- <Text variant="titleLarge" {...props}>
- {children}
- </Text>
+export type TitleLargeProps<E extends React.ElementType = 'span'> = TextProps<E>;
+
+export const TitleLarge = <T extends React.ElementType = 'span'>(props: TitleLargeProps<T>) => (
+ <Text variant="titleLarge" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleMedium.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleMedium.tsx
index 5e188698a4..5c4c2852e6 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleMedium.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/TitleMedium.tsx
@@ -1,8 +1,7 @@
import { Text, TextProps } from './Text';
-export type TitleMediumProps = Omit<TextProps, 'variant'>;
-export const TitleMedium = ({ children, ...props }: TitleMediumProps) => (
- <Text variant="titleMedium" {...props}>
- {children}
- </Text>
+export type TitleMediumProps<E extends React.ElementType = 'span'> = TextProps<E>;
+
+export const TitleMedium = <T extends React.ElementType = 'span'>(props: TitleMediumProps<T>) => (
+ <Text variant="titleMedium" {...props} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts
index 49be1a2718..337ba016c5 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts
@@ -29,7 +29,7 @@ export class NewVersionNotificationProvider implements InAppNotificationProvider
title,
subtitle,
subtitleAction: {
- type: 'navigate',
+ type: 'navigate-internal',
link: {
to: RoutePath.changelog,
onClick: this.context.close,
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/types/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/types/index.ts
index dd810c8061..49666415bf 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/types/index.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/types/index.ts
@@ -1 +1,2 @@
+export * from './polymorphic-props';
export * from './transient-props';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/types/polymorphic-props.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/types/polymorphic-props.ts
new file mode 100644
index 0000000000..d0b9895d35
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/types/polymorphic-props.ts
@@ -0,0 +1,4 @@
+export type PolymorphicProps<E extends React.ElementType, Props = object> = Props &
+ Omit<React.ComponentPropsWithoutRef<E>, keyof Props> & {
+ as?: E;
+ };
diff --git a/desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts b/desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts
index d46f344a09..80a40deef2 100644
--- a/desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts
+++ b/desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts
@@ -1,4 +1,4 @@
-import { LinkProps } from '../../renderer/lib/components';
+import { InternalLinkProps } from '../../renderer/components/InternalLink';
import { Url } from '../constants';
export type NotificationAction = {
@@ -31,8 +31,8 @@ export type InAppNotificationAction =
close: () => void;
}
| {
- type: 'navigate';
- link: Pick<LinkProps, 'to' | 'onClick' | 'aria-label'>;
+ type: 'navigate-internal';
+ link: Pick<InternalLinkProps, 'to' | 'onClick' | 'aria-label'>;
};
export type InAppNotificationIndicatorType = 'success' | 'warning' | 'error';