diff --git a/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.stories.tsx b/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.stories.tsx new file mode 100644 index 00000000000..bf3808cc3a2 --- /dev/null +++ b/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.stories.tsx @@ -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 +> = 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', +} diff --git a/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.tsx b/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.tsx new file mode 100644 index 00000000000..3c004ed7f47 --- /dev/null +++ b/app/src/atoms/buttons/OnDeviceDisplay/LargeButton.tsx @@ -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 ( + + + {buttonText} + + + + ) +} diff --git a/app/src/atoms/buttons/OnDeviceDisplay/__tests__/LargeButton.test.tsx b/app/src/atoms/buttons/OnDeviceDisplay/__tests__/LargeButton.test.tsx new file mode 100644 index 00000000000..cc2fe6ef30b --- /dev/null +++ b/app/src/atoms/buttons/OnDeviceDisplay/__tests__/LargeButton.test.tsx @@ -0,0 +1,63 @@ +import * as React from 'react' +import { renderWithProviders, COLORS } from '@opentrons/components' + +import { LargeButton } from '../LargeButton' + +const render = (props: React.ComponentProps) => { + return renderWithProviders()[0] +} + +describe('LargeButton', () => { + let props: React.ComponentProps + 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') + }) +}) diff --git a/app/src/atoms/buttons/OnDeviceDisplay/index.ts b/app/src/atoms/buttons/OnDeviceDisplay/index.ts index bea30e90c4d..67cb396fe21 100644 --- a/app/src/atoms/buttons/OnDeviceDisplay/index.ts +++ b/app/src/atoms/buttons/OnDeviceDisplay/index.ts @@ -1,3 +1,4 @@ +export { LargeButton } from './LargeButton' export { MediumButtonRounded } from './MediumButtonRounded' export { SmallButton } from './SmallButton' export { TabbedButton } from './TabbedButton'