From d5c82f1e162f57f3299c0a1a321684358eac3c4d Mon Sep 17 00:00:00 2001 From: Brian Arthur Cooper Date: Thu, 9 May 2024 15:37:13 -0400 Subject: [PATCH] feat(components): add new checkbox component and story to atoms (#15137) Include the new checkbox component in the library's ODD-specific atoms. Closes [PLAT-299](https://opentrons.atlassian.net/browse/PLAT-299) --- .../src/atoms/Checkbox/Checkbox.stories.tsx | 24 ++++++ .../Checkbox/__tests__/Checkbox.test.tsx | 55 ++++++++++++ components/src/atoms/Checkbox/index.tsx | 85 +++++++++++++++++++ components/src/atoms/CheckboxField/index.tsx | 4 +- components/src/icons/icon-data.ts | 4 +- 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 components/src/atoms/Checkbox/Checkbox.stories.tsx create mode 100644 components/src/atoms/Checkbox/__tests__/Checkbox.test.tsx create mode 100644 components/src/atoms/Checkbox/index.tsx diff --git a/components/src/atoms/Checkbox/Checkbox.stories.tsx b/components/src/atoms/Checkbox/Checkbox.stories.tsx new file mode 100644 index 00000000000..fc210122882 --- /dev/null +++ b/components/src/atoms/Checkbox/Checkbox.stories.tsx @@ -0,0 +1,24 @@ +import { Checkbox } from './index' + +import type { StoryObj, Meta } from '@storybook/react' + +const meta: Meta = { + title: 'ODD/Atoms/Checkbox', + component: Checkbox, +} + +type Story = StoryObj + +export const Basic: Story = { + args: { + isChecked: true, + labelText: 'Button Text', + onClick: () => { + console.log('clicked') + }, + tabIndex: 1, + disabled: false, + }, +} + +export default meta diff --git a/components/src/atoms/Checkbox/__tests__/Checkbox.test.tsx b/components/src/atoms/Checkbox/__tests__/Checkbox.test.tsx new file mode 100644 index 00000000000..a51f1583a4a --- /dev/null +++ b/components/src/atoms/Checkbox/__tests__/Checkbox.test.tsx @@ -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) => { + return renderWithProviders()[0] +} + +describe('Checkbox', () => { + let props: React.ComponentProps + + 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() + }) +}) diff --git a/components/src/atoms/Checkbox/index.tsx b/components/src/atoms/Checkbox/index.tsx new file mode 100644 index 00000000000..b68bbbe2df4 --- /dev/null +++ b/components/src/atoms/Checkbox/index.tsx @@ -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 ( + + + {labelText} + + + + ) +} + +interface CheckProps { + isChecked: boolean +} +function Check(props: CheckProps): JSX.Element { + return props.isChecked ? ( + + ) : ( + + ) +} diff --git a/components/src/atoms/CheckboxField/index.tsx b/components/src/atoms/CheckboxField/index.tsx index 39e88308231..f416a771186 100644 --- a/components/src/atoms/CheckboxField/index.tsx +++ b/components/src/atoms/CheckboxField/index.tsx @@ -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 */ @@ -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" >