Skip to content

Commit

Permalink
feat(odd): Large Button (#12317)
Browse files Browse the repository at this point in the history
closes RAUT-351
  • Loading branch information
jerader authored Mar 20, 2023
1 parent 055fafa commit dacc8cc
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 0 deletions.
37 changes: 37 additions & 0 deletions app/src/atoms/buttons/OnDeviceDisplay/LargeButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react'
import { LargeButton } from '.'
import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Atoms/Buttons/LargeButton',
argTypes: { onClick: { action: 'clicked' } },
} as Meta

const LargeButtonTemplate: Story<
React.ComponentProps<typeof LargeButton>
> = args => <LargeButton {...args} />

export const PrimaryLargeButton = LargeButtonTemplate.bind({})
PrimaryLargeButton.args = {
buttonText: 'Button text',
buttonType: 'primary',
disabled: false,
}
export const SecondaryLargeButton = LargeButtonTemplate.bind({})
SecondaryLargeButton.args = {
buttonText: 'Button text',
buttonType: 'secondary',
disabled: false,
}
export const AlertLargeButton = LargeButtonTemplate.bind({})
AlertLargeButton.args = {
buttonText: 'Button text',
buttonType: 'alert',
disabled: false,
}
export const CustomIconLargeButton = LargeButtonTemplate.bind({})
CustomIconLargeButton.args = {
buttonText: 'Button text',
buttonType: 'primary',
iconName: 'restart',
}
130 changes: 130 additions & 0 deletions app/src/atoms/buttons/OnDeviceDisplay/LargeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import * as React from 'react'
import { css } from 'styled-components'
import {
TYPOGRAPHY,
COLORS,
SPACING,
BORDERS,
NewPrimaryBtn,
styleProps,
DIRECTION_ROW,
Icon,
} from '@opentrons/components'
import { StyledText } from '../../text'
import type { IconName, StyleProps } from '@opentrons/components'

type LargeButtonTypes = 'primary' | 'secondary' | 'alert'
interface LargeButtonProps extends StyleProps {
onClick: () => void
buttonType: LargeButtonTypes
buttonText: React.ReactNode
iconName?: IconName
disabled?: boolean
}

export function LargeButton(props: LargeButtonProps): JSX.Element {
const { onClick, buttonType, buttonText, iconName, disabled } = props
const buttonProps = {
onClick,
disabled,
}

const LARGE_BUTTON_PROPS_BY_TYPE: Record<
LargeButtonTypes,
{
defaultBackgroundColor: string
activeBackgroundColor: string
defaultColor: string
iconColor: string
}
> = {
secondary: {
defaultColor: COLORS.darkBlackEnabled,
defaultBackgroundColor: COLORS.foundationalBlue,
// TODO(jr, 3/20/23): replace these hex codes with the color constants
activeBackgroundColor: '#99b1d2',
iconColor: COLORS.blueEnabled,
},
alert: {
defaultColor: COLORS.red_one,
defaultBackgroundColor: COLORS.red_three,
activeBackgroundColor: '#c8acad',
iconColor: COLORS.red_one,
},
primary: {
defaultColor: COLORS.white,
defaultBackgroundColor: COLORS.blueEnabled,
activeBackgroundColor: '#2160ca',
iconColor: COLORS.white,
},
}

const LARGE_BUTTON_STYLE = css`
text-align: ${TYPOGRAPHY.textAlignLeft};
color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType].defaultColor};
background-color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType]
.defaultBackgroundColor};
cursor: default;
border-radius: ${BORDERS.size_four};
box-shadow: none;
padding: ${SPACING.spacing5} ${SPACING.spacing5} 2.4375rem;
line-height: ${TYPOGRAPHY.lineHeight20};
text-transform: ${TYPOGRAPHY.textTransformNone};
${TYPOGRAPHY.pSemiBold}
${styleProps}
&:focus {
background-color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType]
.activeBackgroundColor};
box-shadow: none;
}
&:hover {
border: none;
box-shadow: none;
background-color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType]
.defaultBackgroundColor};
color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType].defaultColor};
}
&:focus-visible {
box-shadow: 0 0 0 ${SPACING.spacingS} ${COLORS.fundamentalsFocus};
}
&:active {
background-color: ${LARGE_BUTTON_PROPS_BY_TYPE[buttonType]
.activeBackgroundColor};
}
&:disabled {
background-color: ${COLORS.darkBlack_twenty};
color: ${COLORS.darkBlackEnabled}${COLORS.opacity55HexCode};
}
`
return (
<NewPrimaryBtn
{...buttonProps}
css={LARGE_BUTTON_STYLE}
aria-label={`LargeButton_${buttonType}`}
flexDirection={DIRECTION_ROW}
>
<StyledText
fontSize="2rem"
fontWeight={TYPOGRAPHY.fontWeightSemiBold}
paddingBottom="4.6875rem"
lineHeight="2.625rem"
>
{buttonText}
</StyledText>
<Icon
name={iconName ?? 'play'}
aria-label={`LargeButton_${iconName ?? 'play'}`}
color={
disabled
? COLORS.darkBlack_sixty
: LARGE_BUTTON_PROPS_BY_TYPE[buttonType].iconColor
}
width="1.875rem"
height="1.875rem"
/>
</NewPrimaryBtn>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react'
import { renderWithProviders, COLORS } from '@opentrons/components'

import { LargeButton } from '../LargeButton'

const render = (props: React.ComponentProps<typeof LargeButton>) => {
return renderWithProviders(<LargeButton {...props} />)[0]
}

describe('LargeButton', () => {
let props: React.ComponentProps<typeof LargeButton>
beforeEach(() => {
props = {
onClick: jest.fn(),
buttonType: 'primary',
buttonText: 'large button',
}
})
it('renders the default button and it works as expected', () => {
const { getByText, getByRole } = render(props)
getByText('large button').click()
expect(props.onClick).toHaveBeenCalled()
expect(getByRole('button')).toHaveStyle(
`background-color: ${COLORS.blueEnabled}`
)
})
it('renders the alert button', () => {
props = {
...props,
buttonType: 'alert',
}
const { getByRole } = render(props)
expect(getByRole('button')).toHaveStyle(
`background-color: ${COLORS.red_three}`
)
})
it('renders the secondary button', () => {
props = {
...props,
buttonType: 'secondary',
}
const { getByRole } = render(props)
expect(getByRole('button')).toHaveStyle(
`background-color: ${COLORS.foundationalBlue}`
)
})
it('renders the button as disabled', () => {
props = {
...props,
disabled: true,
}
const { getByRole } = render(props)
expect(getByRole('button')).toBeDisabled()
})
it('renders custom icon in the button', () => {
props = {
...props,
iconName: 'restart',
}
const { getByLabelText } = render(props)
getByLabelText('LargeButton_restart')
})
})
1 change: 1 addition & 0 deletions app/src/atoms/buttons/OnDeviceDisplay/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { LargeButton } from './LargeButton'
export { MediumButtonRounded } from './MediumButtonRounded'
export { SmallButton } from './SmallButton'
export { TabbedButton } from './TabbedButton'

0 comments on commit dacc8cc

Please sign in to comment.