Skip to content

Commit

Permalink
feat(components): add new checkbox component and story to atoms (#15137)
Browse files Browse the repository at this point in the history
Include the new checkbox component in the library's ODD-specific atoms.

Closes [PLAT-299](https://opentrons.atlassian.net/browse/PLAT-299)
  • Loading branch information
b-cooper authored and Carlos-fernandez committed May 20, 2024
1 parent 278510b commit 0e297ee
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 4 deletions.
24 changes: 24 additions & 0 deletions components/src/atoms/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Checkbox } from './index'

import type { StoryObj, Meta } from '@storybook/react'

const meta: Meta<typeof Checkbox> = {
title: 'ODD/Atoms/Checkbox',
component: Checkbox,
}

type Story = StoryObj<typeof Checkbox>

export const Basic: Story = {
args: {
isChecked: true,
labelText: 'Button Text',
onClick: () => {
console.log('clicked')
},
tabIndex: 1,
disabled: false,
},
}

export default meta
55 changes: 55 additions & 0 deletions components/src/atoms/Checkbox/__tests__/Checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from 'react'
import { describe, beforeEach, afterEach, vi, expect, it } from 'vitest'
import { fireEvent, screen } from '@testing-library/react'
import '@testing-library/jest-dom/vitest'
import { renderWithProviders } from '../../../testing/utils'
import { Checkbox } from '..'

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

describe('Checkbox', () => {
let props: React.ComponentProps<typeof Checkbox>

beforeEach(() => {
props = {
onClick: vi.fn(),
isChecked: false,
labelText: 'fake checkbox label',
tabIndex: 1,
disabled: false,
}
})

afterEach(() => {
vi.resetAllMocks()
})

it('renders label with disabled true', () => {
props.disabled = true
render(props)
const checkBoxInput = screen.getByRole('checkbox', {
name: 'fake checkbox label',
})
expect(checkBoxInput).toBeDisabled()
})

it('renders label with correct style - tabIndex 1', () => {
props.tabIndex = 1
render(props)
const checkBoxInput = screen.getByRole('checkbox', {
name: 'fake checkbox label',
})
expect(checkBoxInput).toHaveAttribute('tabindex', '1')
})

it('calls mock function when clicking checkbox', () => {
render(props)
const checkBoxInput = screen.getByRole('checkbox', {
name: 'fake checkbox label',
})
fireEvent.click(checkBoxInput)
expect(props.onClick).toHaveBeenCalled()
})
})
85 changes: 85 additions & 0 deletions components/src/atoms/Checkbox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as React from 'react'
import { css } from 'styled-components'
import { COLORS, BORDERS } from '../../helix-design-system'
import { Flex } from '../../primitives'
import { Icon } from '../../icons'
import {
ALIGN_CENTER,
DIRECTION_ROW,
JUSTIFY_SPACE_BETWEEN,
} from '../../styles'
import { SPACING, TYPOGRAPHY } from '../../ui-style-constants'
import { StyledText } from '../StyledText'

export interface CheckboxProps {
/** checkbox is checked if value is true */
isChecked: boolean
/** label text that describes the option */
labelText: string
/** callback click/tap handler */
onClick: React.MouseEventHandler
/** html tabindex property */
tabIndex?: number
/** if disabled is true, mouse events will not trigger onClick callback */
disabled?: boolean
}
export function Checkbox(props: CheckboxProps): JSX.Element {
const {
isChecked,
labelText,
onClick,
tabIndex = 0,
disabled = false,
} = props
return (
<Flex
as="button"
role="checkbox"
width="100%"
flexDirection={DIRECTION_ROW}
justifyContent={JUSTIFY_SPACE_BETWEEN}
alignItems={ALIGN_CENTER}
padding={SPACING.spacing20}
borderRadius={BORDERS.borderRadius16}
backgroundColor={isChecked ? COLORS.blue50 : COLORS.blue35}
color={isChecked ? COLORS.white : COLORS.black90}
onClick={onClick}
tabIndex={tabIndex}
disabled={disabled}
css={css`
&:active {
background-color: ${isChecked ? COLORS.blue55 : COLORS.blue40};
}
&:focus-visible {
background-color: ${isChecked ? COLORS.blue50 : COLORS.blue35};
outline: 3px ${BORDERS.styleSolid} ${COLORS.blue50};
outline-offset: 2px;
}
&:disabled {
background-color: ${COLORS.grey35};
color: ${COLORS.grey50};
}
`}
>
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{labelText}
</StyledText>
<Check isChecked={isChecked} />
</Flex>
)
}

interface CheckProps {
isChecked: boolean
}
function Check(props: CheckProps): JSX.Element {
return props.isChecked ? (
<Icon name="ot-checkbox" size="1.75rem" color={COLORS.white} />
) : (
<Flex
size="1.75rem"
border={`2px solid ${COLORS.black90}`}
borderRadius={BORDERS.borderRadius4}
/>
)
}
4 changes: 2 additions & 2 deletions components/src/atoms/CheckboxField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SPACING, TYPOGRAPHY } from '../../ui-style-constants'
import { COLORS, BORDERS } from '../../helix-design-system'
import { Flex, Box } from '../../primitives'
import { Icon } from '../../icons'
import { ALIGN_CENTER, JUSTIFY_CENTER, SIZE_1 } from '../../styles'
import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles'

export interface CheckboxFieldProps {
/** change handler */
Expand Down Expand Up @@ -130,7 +130,7 @@ export function CheckboxField(props: CheckboxFieldProps): JSX.Element {
justifyContent={JUSTIFY_CENTER}
borderRadius={BORDERS.borderRadius2}
backgroundColor={COLORS.grey30}
size={SIZE_1}
size="1.25rem"
>
<Box
height="1.5px"
Expand Down
4 changes: 2 additions & 2 deletions components/src/icons/icon-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const ICON_DATA_BY_NAME = {
'checkbox-blank-outline': {
path:
'M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2m0 2v14H5V5h14z',
viewBox: '0 0 24 24',
viewBox: '3 3 18 18',
},
'checkbox-marked': {
path:
Expand Down Expand Up @@ -362,7 +362,7 @@ export const ICON_DATA_BY_NAME = {
'ot-checkbox': {
path:
'M 10.3839,4.5 5.5,9.38388 2.61612,6.5 3.5,5.61612 l 2,2 4,-4 z M 1.5,0 C 0.671573,0 0,0.671573 0,1.5 v 10 C 0,12.3284 0.671573,13 1.5,13 h 10 C 12.3284,13 13,12.3284 13,11.5 V 1.5 C 13,0.671573 12.3284,0 11.5,0 Z',
viewBox: '-1 -1 16 16',
viewBox: '0 0 13 13',
},
'ot-click-and-drag': {
path:
Expand Down

0 comments on commit 0e297ee

Please sign in to comment.