Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 26 additions & 28 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
fontSize,
fontWeight,
lineHeight,
opacity,
radius,
space,
} from '../../theme'
import { css } from '@emotion/react'
import { Spinner } from '../Spinner'
import { transparentize, transparentGradient } from '../../utils/colors'

export enum ButtonVariant {
primary = 'primary',
Expand Down Expand Up @@ -67,11 +69,7 @@ const StyledButton = styled.button<StyledButtonProps>`
justify-content: center;
font-family: inherit;
font-weight: ${fontWeight.semiBold};
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.24),
rgba(255, 255, 255, 0)
);
background-image: ${transparentGradient('currentColor', 'to bottom', .24, 0)};
line-height: ${lineHeight.solid};
align-items: center;

Expand All @@ -86,7 +84,7 @@ const StyledButton = styled.button<StyledButtonProps>`
inset: -1px;
background-color: transparent;
border-radius: calc(${radius.md} + 1px);
box-shadow: 0 0 0 ${space[4]} ${color.actionFocus};
outline: ${space[4]} solid ${transparentize(color.action, opacity.statusFocusColor)};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for this change is because color-mix doesn't play nicely with css variables + box-shadow (yet)

pointer-events: none;
}

Expand All @@ -96,11 +94,7 @@ const StyledButton = styled.button<StyledButtonProps>`
}

&:hover {
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.48),
rgba(255, 255, 255, 0.24)
);
background-image: ${transparentGradient('currentColor', 'to bottom', .48, .24)};
}

${({ disabled }) =>
Expand Down Expand Up @@ -165,12 +159,12 @@ const StyledButton = styled.button<StyledButtonProps>`
${({ variant }) =>
variant === ButtonVariant.secondary &&
css`
background-color: ${color.actionBackgroundAlpha12};
background-color: ${color.actionBackground};
color: ${color.action};
background-image: unset;

&:hover {
background-image: unset;
background-image: ${transparentGradient('currentColor', 'to top', .2, .1)};
}
`};

Expand All @@ -179,13 +173,14 @@ const StyledButton = styled.button<StyledButtonProps>`
css`
background-color: ${color.failureBackground};
color: ${color.failure};
background-image: unset;

[data-theme='dark'] & {
background-image: unset;
&:hover {
background-image: ${transparentGradient('currentColor', 'to top', .2, .1)};
}

&:focus::after {
box-shadow: 0 0 0 ${space[4]} ${color.failureFocus};
outline-color: ${transparentize(color.failure, opacity.statusFocusColor)};
}
`};

Expand All @@ -196,7 +191,7 @@ const StyledButton = styled.button<StyledButtonProps>`
color: ${color.onSuccess};

&:focus::after {
box-shadow: 0 0 0 ${space[4]} ${color.successFocus};
outline-color: ${transparentize(color.success, opacity.statusFocusColor)};
}
`};

Expand All @@ -207,7 +202,7 @@ const StyledButton = styled.button<StyledButtonProps>`
color: ${color.onWarning};

&:focus::after {
box-shadow: 0 0 0 ${space[4]} ${color.warningFocus};
outline-color: ${transparentize(color.warning, opacity.statusFocusColor)};
}
`};

Expand All @@ -218,7 +213,7 @@ const StyledButton = styled.button<StyledButtonProps>`
color: ${color.onFailure};

&:focus::after {
box-shadow: 0 0 0 ${space[4]} ${color.failureFocus};
outline-color: ${transparentize(color.failure, opacity.statusFocusColor)};
}
`};

Expand All @@ -227,10 +222,15 @@ const StyledButton = styled.button<StyledButtonProps>`
css`
background-color: ${color.background};
color: ${color.action};
background-image: unset;

[data-theme='dark'] & {
background-image: unset;
}

&:hover {
background-image: ${transparentGradient('currentColor', 'to top', .2, .1)};
}
`};

${({ variant }) =>
Expand All @@ -240,7 +240,7 @@ const StyledButton = styled.button<StyledButtonProps>`
color: #ffffff;

&:focus::after {
box-shadow: 0 0 0 ${space[4]} #1777f252;
outline-color: ${transparentize('#1777f2', opacity.statusFocusColor)};
}
`};

Expand All @@ -250,14 +250,8 @@ const StyledButton = styled.button<StyledButtonProps>`
background-color: ${color.foreground};
color: ${color.background};

[data-theme='dark'] & {
&:focus::after {
box-shadow: 0 0 0 ${space[4]} #ffffff52;
}
}

&:focus::after {
box-shadow: 0 0 0 ${space[4]} #1a212952;
outline-color: ${transparentize(color.foreground, opacity.statusFocusColor)};
}
`};

Expand All @@ -269,8 +263,12 @@ const StyledButton = styled.button<StyledButtonProps>`
border: 1px solid ${color.lightElevatedBackground};
background-image: unset;

&:hover {
background-image: ${transparentGradient('currentColor', 'to top', .1, 0)};
}

&:focus::after {
box-shadow: 0 0 0 ${space[4]} #ccd0d152;
outline-color: ${transparentize('#ccd0d1', opacity.statusFocusColor)};
}
`};
`
Expand Down
5 changes: 3 additions & 2 deletions src/components/Card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
fontWeight,
device,
lineHeight,
opacity,
} from '../../theme'
import { transparentize } from '../../utils/colors'

export enum CardVerticalAlign {
top = 'top',
Expand Down Expand Up @@ -80,8 +82,7 @@ const Container = styled.div<StyledCardProps>`
}

&:focus {
box-shadow: 0 0 0 ${space[4]} ${color.actionFocus};
outline: 0;
outline: ${space[4]} solid ${transparentize(color.action, opacity.statusFocusColor)};
}
`

Expand Down
3 changes: 2 additions & 1 deletion src/components/Dropzone/Dropzone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { BaseButton } from '../BaseButton'
import { Button } from '../Button'
import { FilesIllustration } from './FilesIllustration'
import { ArrowUpRounded } from '../../icons'
import { transparentize } from '../../utils/colors'

interface DropOverlayProps {
isDragging: boolean
Expand Down Expand Up @@ -114,7 +115,7 @@ const DropArea = styled.div<DropAreaStyles>`
border-width: 2px;
border-style: dashed;
border-color: ${({ variant }) =>
variant === DropzoneVariant.light ? color.actionFocus : color.action};
variant === DropzoneVariant.light ? transparentize(color.action, .5) : color.action};
}
`

Expand Down
7 changes: 5 additions & 2 deletions src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import {
radius,
device,
fontWeight,
opacity,
} from '../../theme'
import { CloseRounded } from '../../icons'
import { transparentize } from '../../utils/colors'

export interface InputProps extends React.HTMLAttributes<HTMLInputElement> {
id: string
Expand Down Expand Up @@ -109,8 +111,9 @@ export const fieldStyles = (props: InputProps) => css`
background-color: ${props.invalid
? color.failureBackground
: color.elevatedBackground};
box-shadow: 0 0 0 ${space[4]}
${props.invalid ? color.failureFocus : color.actionFocus};
outline: ${space[4]} solid
${props.invalid ? color.failureFocus :
transparentize(color.action, opacity.statusFocusColor)};
}

&::placeholder {
Expand Down
6 changes: 3 additions & 3 deletions src/components/RadioGroup/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import styled from '@emotion/styled'
import React, { forwardRef, InputHTMLAttributes, Ref } from 'react'
import { color, space, transition } from '../..'
import { color, opacity, space, transition } from '../..'
import { Checkmark } from '../../icons'
import { transparentize } from '../../utils/colors'

const Container = styled.span`
position: relative;
Expand Down Expand Up @@ -46,8 +47,7 @@ const StyledInput = styled.input`

&:focus,
&:active {
outline: 0;
box-shadow: 0 0 0 ${space[4]} ${color.actionFocus};
outline: ${space[4]} solid ${transparentize(color.action, opacity.statusFocusColor)};
}
`

Expand Down
5 changes: 3 additions & 2 deletions src/components/Toggle/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import styled from '@emotion/styled'
import { Spinner } from '../Spinner'
import { space, color } from '../../theme'
import { space, color, opacity } from '../../theme'
import { transparentize } from '../../utils/colors'

export interface SwitchProps {
on: boolean
Expand Down Expand Up @@ -76,7 +77,7 @@ const Button = styled.button<ButtonProps>`
inset: -1px;
background-color: transparent;
border-radius: ${space[32]};
box-shadow: 0 0 0 ${space[4]} ${color.actionFocus};
outline: ${space[4]} solid ${transparentize(color.action, opacity.statusFocusColor)};
pointer-events: none;
}
`
Expand Down
10 changes: 4 additions & 6 deletions src/global-styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { css } from '@emotion/react'
import { space, radius, color } from './theme'
import { space, radius, color, opacity } from './theme'
import { baseTextStyles } from './components/Text'
import { transparentize } from './utils/colors'

export const globalStyles = css`
:root {
Expand Down Expand Up @@ -73,10 +74,8 @@ export const globalStyles = css`

// Action
--action: var(--earth400);
--actionBackground: var(--earth50);
--actionBackground: ${transparentize(color.action, opacity.statusBackgroundColor)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this always have an opacity? It introduces this bug again:

CleanShot 2023-05-23 at 15 27 21@2x

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, will use a new activeBackground here instead so we can distinguish the two use-cases

--onAction: var(--nova);
--actionFocus: #00b6f052;
--actionBackgroundAlpha12: #00b6f01f;

// Success
--success: var(--titan400);
Expand All @@ -100,7 +99,6 @@ export const globalStyles = css`
--info: var(--earth400);
--infoBackground: var(--earth50);
--onInfo: var(--nova);
--actionFocus: #00b6f052;

// Inactive
--inactive: var(--stardust500);
Expand Down Expand Up @@ -292,7 +290,7 @@ export const globalStyles = css`

&:focus {
outline: 0;
box-shadow: 0 0 0 ${space[4]} ${color.actionFocus};
box-shadow: 0 0 0 ${space[4]} ${transparentize('currentColor', opacity.statusFocusColor)};
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ export const color = {
action: 'var(--action)',
actionBackground: 'var(--actionBackground)',
onAction: 'var(--onAction)',
actionFocus: 'var(--actionFocus)',
actionBackgroundAlpha12: 'var(--actionBackgroundAlpha12)',
success: 'var(--success)',
successBackground: 'var(--successBackground)',
onSuccess: 'var(--onSuccess)',
Expand Down Expand Up @@ -54,6 +52,11 @@ export const color = {
overlay: 'var(--overlay)',
} as const

export const opacity = {
statusBackgroundColor: .1,
statusFocusColor: .5
} as const

export const fontStack = `'Proxima Nova', -apple-system, BlinkMacSystemFont,
'avenir next', avenir, 'helvetica neue', helvetica, ubuntu, roboto, noto,
'segoe ui', arial, sans-serif`
Expand Down
29 changes: 29 additions & 0 deletions src/utils/colors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Utility function to apply transparency to a color (variable) using `color-mix`
* @param {string} color - The color to make transparent. Can be a theme variabale, a hex code or "currentColor"
* @param {number} opacity - The desired opacity, a number between 0 and 1
*/
Comment on lines +1 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should live inside the commit message instead of a comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plus side of this for me was that the tooltip of the function will explain what is needed, which I thought would be helpful for the opacity specifically (there are a number of correct ways to pass that through). Any alternative method for that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like it tbh, but since it's not a practice in my codebase it seems a bit inconsistent to me 🤷 but yeah not sure what the others think.

export const transparentize = (color: string, opacity: number) => {
const parsedColor = color === 'currentColor' ? 'currentColor' :
color.charAt(0) === '#' ? color :
color.indexOf('var(--') !== -1 ? color : `var(--${color})`

const parsedOpacity = 100 - (opacity * 100)

return `color-mix(in srgb, ${parsedColor}, transparent ${parsedOpacity}%)`
}

export const transparentGradient = (color: string, direction: string, fromOpacity: number, toOpacity: number) => {
const parsedColor = color === 'currentColor' ? 'currentColor' :
color.charAt(0) === '#' ? color :
color.indexOf('var(--') !== -1 ? color : `var(--${color})`

const parsedFromOpacity = 100 - (fromOpacity * 100)
const parsedToOpacity = 100 - (toOpacity * 100)

return `linear-gradient(
${direction},
color-mix(in srgb, ${parsedColor}, transparent ${parsedFromOpacity}%),
color-mix(in srgb, ${parsedColor}, transparent ${parsedToOpacity}%)
)`
}
Comment on lines +1 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put them in their own files, import them here and then export them from colors/index.ts.