summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-09-26 11:06:20 +0200
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-09-26 11:06:20 +0200
commit7a21043f4629332de2f8b9fd61c3dc0ee648cb67 (patch)
treeedba318279b7e253dfd867921d3e23d015438295
parent10400ce365fdd0faeec3ee7b0c60abdf0c597036 (diff)
parent80a45a5096dac60481c18315cb12e025a46a8262 (diff)
downloadmullvadvpn-7a21043f4629332de2f8b9fd61c3dc0ee648cb67.tar.xz
mullvadvpn-7a21043f4629332de2f8b9fd61c3dc0ee648cb67.zip
Merge branch 'fix-icon-button-states'
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/Button.tsx15
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/ButtonIcon.tsx (renamed from desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonIcon.tsx)4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-text/ButtonText.tsx (renamed from desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonText.tsx)4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-text/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/index.ts4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx87
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx68
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/IconButtonIcon.tsx12
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/index.ts1
11 files changed, 97 insertions, 101 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/Button.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/Button.tsx
index 27bda0a6d8..0b5e05afa4 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/Button.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/Button.tsx
@@ -1,14 +1,14 @@
-import React, { forwardRef } from 'react';
+import React from 'react';
import styled, { css } from 'styled-components';
import { colors, Radius, spacings } from '../../foundations';
import { ButtonProvider } from './ButtonContext';
import { ButtonIcon, ButtonText, StyledButtonIcon, StyledButtonText } from './components';
-export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+export type ButtonProps = React.ComponentPropsWithRef<'button'> & {
variant?: 'primary' | 'success' | 'destructive';
width?: 'fill' | 'fit';
-}
+};
const styles = {
radius: Radius.radius4,
@@ -123,18 +123,15 @@ export const StyledButton = styled.button<ButtonProps>`
}}
`;
-const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
- { children, disabled = false, style, ...props },
- ref,
-) {
+function Button({ children, disabled = false, ...props }: ButtonProps) {
return (
<ButtonProvider disabled={disabled}>
- <StyledButton ref={ref} disabled={disabled} {...props}>
+ <StyledButton disabled={disabled} {...props}>
{children}
</StyledButton>
</ButtonProvider>
);
-});
+}
const ButtonNamespace = Object.assign(Button, {
Text: ButtonText,
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/ButtonIcon.tsx
index 94054d909d..ad07a442da 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/ButtonIcon.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/ButtonIcon.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components';
-import { Icon, IconProps } from '../../icon';
-import { useButtonContext } from '../ButtonContext';
+import { Icon, IconProps } from '../../../icon';
+import { useButtonContext } from '../../ButtonContext';
type ButtonIconProps = Omit<IconProps, 'size'>;
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/index.ts
new file mode 100644
index 0000000000..d016c203ef
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-icon/index.ts
@@ -0,0 +1 @@
+export * from './ButtonIcon';
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/button-text/ButtonText.tsx
index 79e8291142..202318995a 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/button-text/ButtonText.tsx
@@ -1,8 +1,8 @@
import React from 'react';
import styled from 'styled-components';
-import { BodySmallSemiBold, BodySmallSemiBoldProps } from '../../typography';
-import { useButtonContext } from '../ButtonContext';
+import { BodySmallSemiBold, BodySmallSemiBoldProps } from '../../../typography';
+import { useButtonContext } from '../../ButtonContext';
export type ButtonTextProps<T extends React.ElementType = 'span'> = BodySmallSemiBoldProps<T>;
export const StyledButtonText = styled(BodySmallSemiBold)``;
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-text/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-text/index.ts
new file mode 100644
index 0000000000..8cfa5f2b8d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/button-text/index.ts
@@ -0,0 +1 @@
+export * from './ButtonText';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/index.ts
index 904258378e..26e29b335d 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/index.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/button/components/index.ts
@@ -1,2 +1,2 @@
-export * from './ButtonIcon';
-export * from './ButtonText';
+export * from './button-icon';
+export * from './button-text';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
index fa363c6e3b..ee3caa25cb 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
@@ -1,50 +1,101 @@
-import React, { forwardRef } from 'react';
+import React from 'react';
import styled, { css } from 'styled-components';
import { colors } from '../../foundations';
import { IconProps, iconSizes } from '../icon/Icon';
-import { IconButtonIcon } from './components/IconButtonIcon';
+import { IconButtonIcon, StyledIconButtonIcon } from './components';
import { IconButtonProvider } from './IconButtonContext';
export type IconButtonVariant = 'primary' | 'secondary';
-export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+export type IconButtonProps = React.ComponentPropsWithRef<'button'> & {
variant?: IconButtonVariant;
size?: IconProps['size'];
-}
+};
-const StyledButton = styled.button<{ $size: IconButtonProps['size'] }>`
- ${({ $size = 'medium' }) => {
+const variants: Record<
+ IconButtonVariant,
+ {
+ background: string;
+ hover: string;
+ pressed: string;
+ disabled: string;
+ }
+> = {
+ primary: {
+ background: colors.white,
+ hover: colors.whiteAlpha60,
+ pressed: colors.whiteAlpha40,
+ disabled: colors.whiteAlpha40,
+ },
+ secondary: {
+ background: colors.whiteAlpha60,
+ hover: colors.whiteAlpha80,
+ pressed: colors.white,
+ disabled: colors.whiteAlpha40,
+ },
+} as const;
+
+const StyledButton = styled.button<{
+ $size: IconButtonProps['size'];
+ $variant: IconButtonVariant;
+}>`
+ ${({ $size = 'medium', $variant = 'primary' }) => {
const size = iconSizes[$size];
+ const variant = variants[$variant];
return css`
--size: ${size}px;
+ --background: ${variant.background};
+ --hover: ${variant.hover};
+ --pressed: ${variant.pressed};
+ --disabled: ${variant.disabled};
+ --transition-duration: 0.15s;
+
background: ${colors.transparent};
height: var(--size);
width: var(--size);
border-radius: 100%;
- &:focus-visible {
+
+ &&:focus-visible {
outline: 2px solid ${colors.white};
outline-offset: 1px;
}
+
+ ${StyledIconButtonIcon} {
+ background-color: var(--background);
+ @media (prefers-reduced-motion: no-preference) {
+ transition: background-color var(--transition-duration) ease;
+ }
+ }
+
+ &&:not(:disabled):hover ${StyledIconButtonIcon} {
+ --transition-duration: 0s;
+ background-color: var(--hover);
+ }
+
+ &&:not(:disabled):active ${StyledIconButtonIcon} {
+ --transition-duration: 0s;
+ background-color: var(--pressed);
+ }
+
+ &&:disabled ${StyledIconButtonIcon} {
+ background-color: var(--disabled);
+ }
`;
}}
`;
-const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
- ({ variant = 'primary', size = 'medium', disabled, style, ...props }, ref) => {
- return (
- <IconButtonProvider size={size} variant={variant} disabled={disabled}>
- <StyledButton ref={ref} disabled={disabled} $size={size} {...props} />
- </IconButtonProvider>
- );
- },
-);
+function IconButton({ variant = 'primary', size = 'medium', disabled, ...props }: IconButtonProps) {
+ return (
+ <IconButtonProvider size={size} variant={variant} disabled={disabled}>
+ <StyledButton disabled={disabled} $variant={variant} $size={size} {...props} />
+ </IconButtonProvider>
+ );
+}
const IconButtonNamespace = Object.assign(IconButton, {
Icon: IconButtonIcon,
});
export { IconButtonNamespace as IconButton };
-
-IconButton.displayName = 'Button';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx
deleted file mode 100644
index 6247cbb6b9..0000000000
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import styled, { css } from 'styled-components';
-
-import { colors } from '../../../foundations';
-import { Icon, IconProps } from '../../icon/Icon';
-import { IconButtonVariant } from '../IconButton';
-import { useIconButtonContext } from '../IconButtonContext';
-export type IconButtonIconProps = IconProps;
-
-const variants: Record<
- IconButtonVariant,
- {
- background: string;
- hover: string;
- pressed: string;
- disabled: string;
- }
-> = {
- primary: {
- background: colors.white,
- hover: colors.whiteAlpha60,
- pressed: colors.whiteAlpha40,
- disabled: colors.whiteAlpha40,
- },
- secondary: {
- background: colors.whiteAlpha60,
- hover: colors.whiteAlpha80,
- pressed: colors.white,
- disabled: colors.whiteAlpha40,
- },
-} as const;
-
-const StyledIconButtonIcon = styled(Icon)<{ $variant: IconButtonVariant }>(({ $variant }) => {
- const variant = variants[$variant];
- return css`
- --background: ${variant.background};
- --hover: ${variant.hover};
- --pressed: ${variant.pressed};
- --disabled: ${variant.disabled};
- --transition-duration: 0.15s;
-
- @media (prefers-reduced-motion: no-preference) {
- transition: background-color var(--transition-duration) ease;
- }
-
- background-color: var(--background);
-
- &&:not([data-disabled]):hover {
- --transition-duration: 0s;
- background-color: var(--hover);
- }
-
- &&:not([data-disabled]):active {
- --transition-duration: 0s;
- background-color: var(--pressed);
- }
-
- &[data-disabled='true'] {
- background-color: var(--disabled);
- }
- `;
-});
-
-export const IconButtonIcon = (props: IconButtonIconProps) => {
- const { variant = 'primary', size, disabled } = useIconButtonContext();
- return (
- <StyledIconButtonIcon size={size} data-disabled={disabled} $variant={variant} {...props} />
- );
-};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/IconButtonIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/IconButtonIcon.tsx
new file mode 100644
index 0000000000..31892ff4ee
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/IconButtonIcon.tsx
@@ -0,0 +1,12 @@
+import styled from 'styled-components';
+
+import { Icon, IconProps } from '../../../icon/Icon';
+import { useIconButtonContext } from '../../IconButtonContext';
+export type IconButtonIconProps = IconProps;
+
+export const StyledIconButtonIcon = styled(Icon)``;
+
+export const IconButtonIcon = (props: IconButtonIconProps) => {
+ const { size } = useIconButtonContext();
+ return <StyledIconButtonIcon size={size} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/index.ts
new file mode 100644
index 0000000000..970aa41372
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/icon-button-icon/index.ts
@@ -0,0 +1 @@
+export * from './IconButtonIcon';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/index.ts
new file mode 100644
index 0000000000..cb56fa6cb5
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/index.ts
@@ -0,0 +1 @@
+export * from './icon-button-icon';