From d8e9d5583eede8f3dbe553b8a47f859654a3cc7b Mon Sep 17 00:00:00 2001 From: koji Date: Wed, 19 Jul 2023 12:42:27 -0400 Subject: [PATCH] feat(app): add ListItem component (#13128) * feat(app): add ListItem component --- app/src/atoms/ListItem/ListItem.stories.tsx | 39 +++++++++++ .../ListItem/__tests__/ListItem.test.tsx | 68 +++++++++++++++++++ app/src/atoms/ListItem/index.tsx | 51 ++++++++++++++ .../EstopModal/EstopPressedModal.tsx | 10 ++- 4 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 app/src/atoms/ListItem/ListItem.stories.tsx create mode 100644 app/src/atoms/ListItem/__tests__/ListItem.test.tsx create mode 100644 app/src/atoms/ListItem/index.tsx diff --git a/app/src/atoms/ListItem/ListItem.stories.tsx b/app/src/atoms/ListItem/ListItem.stories.tsx new file mode 100644 index 00000000000..3f7cc3da4b3 --- /dev/null +++ b/app/src/atoms/ListItem/ListItem.stories.tsx @@ -0,0 +1,39 @@ +import * as React from 'react' +import { DIRECTION_COLUMN, Flex, SPACING } from '@opentrons/components' +import { StyledText } from '../text' +import { ListItem } from '.' +import type { Story, Meta } from '@storybook/react' + +export default { + title: 'ODD/Atoms/ListItem', + argTypes: { + type: { + control: { + type: 'select', + options: ['error', 'noActive', 'success', 'warning'], + }, + }, + }, +} as Meta + +const ListItemTemplate: Story> = args => ( + +) + +export const Item = ListItemTemplate.bind({}) +Item.args = { + type: 'noActive', + children: ( + + + Slot Component: Replace me using the component panel. + + + Slot Component: Replace me using the component panel. + + + Slot Component: Replace me using the component panel. + + + ), +} diff --git a/app/src/atoms/ListItem/__tests__/ListItem.test.tsx b/app/src/atoms/ListItem/__tests__/ListItem.test.tsx new file mode 100644 index 00000000000..0f17babdf1b --- /dev/null +++ b/app/src/atoms/ListItem/__tests__/ListItem.test.tsx @@ -0,0 +1,68 @@ +import * as React from 'react' + +import { + BORDERS, + COLORS, + renderWithProviders, + SPACING, +} from '@opentrons/components' + +import { ListItem } from '..' + +const render = (props: React.ComponentProps) => + renderWithProviders() + +describe('ListItem', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + type: 'error', + children:
mock listitem content
, + } + }) + + it('should render correct style - error', () => { + const [{ getByText, getByTestId }] = render(props) + getByText('mock listitem content') + const listItem = getByTestId('ListItem_error') + expect(listItem).toHaveStyle(`backgroundColor: ${COLORS.red3}`) + expect(listItem).toHaveStyle( + `padding: ${SPACING.spacing16} ${SPACING.spacing24}` + ) + expect(listItem).toHaveStyle(`borderRadius: ${BORDERS.borderRadiusSize3}`) + }) + it('should render correct style - noActive', () => { + props.type = 'noActive' + const [{ getByText, getByTestId }] = render(props) + getByText('mock listitem content') + const listItem = getByTestId('ListItem_noActive') + expect(listItem).toHaveStyle(`backgroundColor: ${COLORS.light1}`) + expect(listItem).toHaveStyle( + `padding: ${SPACING.spacing16} ${SPACING.spacing24}` + ) + expect(listItem).toHaveStyle(`borderRadius: ${BORDERS.borderRadiusSize3}`) + }) + it('should render correct style - success', () => { + props.type = 'success' + const [{ getByText, getByTestId }] = render(props) + getByText('mock listitem content') + const listItem = getByTestId('ListItem_success') + expect(listItem).toHaveStyle(`backgroundColor: ${COLORS.green3}`) + expect(listItem).toHaveStyle( + `padding: ${SPACING.spacing16} ${SPACING.spacing24}` + ) + expect(listItem).toHaveStyle(`borderRadius: ${BORDERS.borderRadiusSize3}`) + }) + it('should render correct style - warning', () => { + props.type = 'warning' + const [{ getByText, getByTestId }] = render(props) + getByText('mock listitem content') + const listItem = getByTestId('ListItem_warning') + expect(listItem).toHaveStyle(`backgroundColor: ${COLORS.yellow3}`) + expect(listItem).toHaveStyle( + `padding: ${SPACING.spacing16} ${SPACING.spacing24}` + ) + expect(listItem).toHaveStyle(`borderRadius: ${BORDERS.borderRadiusSize3}`) + }) +}) diff --git a/app/src/atoms/ListItem/index.tsx b/app/src/atoms/ListItem/index.tsx new file mode 100644 index 00000000000..1ce33bb9cb2 --- /dev/null +++ b/app/src/atoms/ListItem/index.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' + +import { BORDERS, COLORS, Flex, SPACING } from '@opentrons/components' + +import type { StyleProps } from '@opentrons/components' + +export type ListItemType = 'error' | 'noActive' | 'success' | 'warning' + +interface ListItemProps extends StyleProps { + /** ListItem state type */ + type: ListItemType + /** ListItem contents */ + children: React.ReactNode +} + +const LISTITEM_PROPS_BY_TYPE: Record< + ListItemType, + { backgroundColor: string } +> = { + error: { + backgroundColor: COLORS.red3, + }, + noActive: { + backgroundColor: COLORS.light1, + }, + success: { + backgroundColor: COLORS.green3, + }, + warning: { + backgroundColor: COLORS.yellow3, + }, +} + +export function ListItem(props: ListItemProps): JSX.Element { + const { type, children, ...styleProps } = props + const listItemProps = LISTITEM_PROPS_BY_TYPE[type] + + return ( + + {children} + + ) +} diff --git a/app/src/organisms/EstopModal/EstopPressedModal.tsx b/app/src/organisms/EstopModal/EstopPressedModal.tsx index 9c81d510f52..b4de4e2f2bb 100644 --- a/app/src/organisms/EstopModal/EstopPressedModal.tsx +++ b/app/src/organisms/EstopModal/EstopPressedModal.tsx @@ -3,7 +3,6 @@ import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { ALIGN_CENTER, - BORDERS, COLORS, DIRECTION_COLUMN, DIRECTION_ROW, @@ -17,6 +16,7 @@ import { import { Banner } from '../../atoms/Banner' import { Chip } from '../../atoms/Chip' +import { ListItem } from '../../atoms/ListItem' import { SmallButton } from '../../atoms/buttons' import { StyledText } from '../../atoms/text' import { LegacyModal } from '../../molecules/LegacyModal' @@ -72,10 +72,8 @@ function TouchscreenModal({ {t('estop_pressed_description')} - - +