diff options
| author | Oliver <oliver@mohlin.dev> | 2024-12-10 14:09:42 +0100 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-12-17 12:15:39 +0100 |
| commit | 101406af03e85a35becec2ecfd3f1c439ee564e9 (patch) | |
| tree | 0bbe13f43e8f72d6ea0bccc93d07426112285e84 | |
| parent | a68ef5cf39e79310ebe0a7891e2b5312da467136 (diff) | |
| download | mullvadvpn-101406af03e85a35becec2ecfd3f1c439ee564e9.tar.xz mullvadvpn-101406af03e85a35becec2ecfd3f1c439ee564e9.zip | |
Add Button and IconButton components
5 files changed, 183 insertions, 0 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/button-reset.ts b/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/button-reset.ts new file mode 100644 index 0000000000..4ef5844150 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/button-reset.ts @@ -0,0 +1,10 @@ +export const buttonReset = { + border: 'none', + padding: 0, + margin: 0, + font: 'inherit', + color: 'inherit', + textAlign: 'inherit', + lineHeight: 'inherit', + cursor: 'default', +} as React.CSSProperties; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/index.ts new file mode 100644 index 0000000000..c546f737b6 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/common/mixins/index.ts @@ -0,0 +1 @@ +export * from './button-reset'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/Button.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/Button.tsx new file mode 100644 index 0000000000..c4db496a21 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/Button.tsx @@ -0,0 +1,105 @@ +import React, { forwardRef } from 'react'; +import styled from 'styled-components'; + +import { Colors, Radius, Spacings } from '../../../tokens'; +import { Flex } from '../layout'; +import { buttonReset } from '../mixins'; +import { BodySmallSemiBold } from '../text'; + +export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { + variant?: 'primary' | 'success' | 'destructive'; + size?: 'tiny' | 'small' | 'regular' | 'full' | '1/2'; + leading?: React.ReactNode; + trailing?: React.ReactNode; +} + +const variants = { + primary: { + background: Colors.blue, + hover: Colors.blue60, + disabled: Colors.blue50, + }, + success: { + background: Colors.green, + hover: Colors.green90, + disabled: Colors.green40, + }, + destructive: { + background: Colors.red, + hover: Colors.red80, + disabled: Colors.red60, + }, +} as const; + +const sizes = { + tiny: '44px', + small: '60px', + regular: '272px', + full: '100%', + '1/2': '50%', +}; + +const StyledButton = styled.button({ + ...buttonReset, + + minHeight: '32px', + borderRadius: Radius.radius4, + width: 'var(--size)', + background: 'var(--background)', + '&:not(:disabled):hover': { + background: 'var(--hover)', + }, + '&:disabled': { + background: 'var(--disabled)', + }, + '&:focus-visible': { + outline: `2px solid ${Colors.white}`, + outlineOffset: '2px', + }, +}); + +export const Button = forwardRef<HTMLButtonElement, ButtonProps>( + ( + { variant = 'primary', size = 'regular', leading, trailing, children, disabled, ...props }, + ref, + ) => { + const styles = variants[variant]; + return ( + <StyledButton + ref={ref} + style={ + { + '--background': styles.background, + '--hover': styles.hover, + '--disabled': styles.disabled, + '--size': sizes[size], + } as React.CSSProperties + } + disabled={disabled} + {...props}> + <Flex + $flex={1} + $gap={Spacings.spacing4} + $justifyContent="space-between" + $padding={{ + horizontal: Spacings.spacing3, + }} + $alignItems="center"> + {leading} + <Flex $flex={1} $justifyContent="center" $alignItems="center"> + {typeof children === 'string' ? ( + <BodySmallSemiBold color={disabled ? Colors.white40 : Colors.white}> + {children} + </BodySmallSemiBold> + ) : ( + children + )} + </Flex> + {trailing} + </Flex> + </StyledButton> + ); + }, +); + +Button.displayName = 'Button'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/IconButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/IconButton.tsx new file mode 100644 index 0000000000..bdbe7ba8e4 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/IconButton.tsx @@ -0,0 +1,65 @@ +import React, { forwardRef } from 'react'; +import styled from 'styled-components'; + +import { Colors } from '../../../tokens'; +import ImageView from '../../ImageView'; +import { buttonReset } from '../mixins'; + +export interface IconButtonProps + extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> { + variant?: 'primary' | 'secondary'; + size?: 'small' | 'regular'; + icon: string; +} + +const variants = { + primary: { + background: Colors.white, + hover: Colors.white60, + disabled: Colors.white50, + }, + secondary: { + background: Colors.white60, + hover: Colors.white80, + disabled: Colors.white50, + }, +} as const; + +const sizes = { + small: 16, + regular: 24, +}; + +const StyledButton = styled.button({ + ...buttonReset, + + background: 'transparent', + height: 'var(--size)', + width: 'var(--size)', + '&:focus-visible': { + outline: `2px solid ${Colors.white}`, + outlineOffset: '2px', + borderRadius: '100%', + }, +}); + +export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>( + ({ icon, variant = 'primary', size: sizeProp = 'regular', disabled, ...props }, ref) => { + const styles = variants[variant]; + const size = sizes[sizeProp]; + return ( + <StyledButton ref={ref} disabled={disabled} {...props}> + <ImageView + source={icon} + tintColor={styles.background} + tintHoverColor={styles.hover} + disabled={disabled} + height={size} + width={size} + /> + </StyledButton> + ); + }, +); + +IconButton.displayName = 'Button'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/index.ts new file mode 100644 index 0000000000..66f0cf90a7 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/common/molecules/index.ts @@ -0,0 +1,2 @@ +export * from './Button'; +export * from './IconButton'; |
