Skip to content

Commit

Permalink
feat(odd): menuList and MenuItem ODD support (#12511)
Browse files Browse the repository at this point in the history
closes RAUT-403
  • Loading branch information
jerader committed Apr 19, 2023
1 parent 71295f5 commit 066e13e
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 210 deletions.
20 changes: 16 additions & 4 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
}

import React from 'react'
import { I18nextProvider } from 'react-i18next'
import { GlobalStyle } from '../app/src/atoms/GlobalStyle'
import { i18n } from '../app/src/i18n'

export const customViewports = {
onDeviceDisplay: {
name: 'Touchscreen',
type: 'tablet',
styles: {
width: '1024px',
height: '600px',
},
},
}

export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
viewport: { viewports: customViewports },
}

// Global decorator to apply the styles to all stories
export const decorators = [
Story => (
Expand Down
7 changes: 7 additions & 0 deletions app/src/atoms/MenuList/MenuItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ const Template: Story<React.ComponentProps<typeof MenuItem>> = args => (
export const Primary = Template.bind({})
Primary.args = {
children: 'Example menu btn',
disabled: false,
}

Primary.parameters = {
viewport: {
defaultViewport: 'onDeviceDisplay',
},
}
48 changes: 37 additions & 11 deletions app/src/atoms/MenuList/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
import styled from 'styled-components'
import {
SPACING,
Btn,
COLORS,
TEXT_ALIGN_LEFT,
TYPOGRAPHY,
ALIGN_CENTER,
RESPONSIVENESS,
StyleProps,
} from '@opentrons/components'

import type { PrimitiveComponent } from '@opentrons/components'

type BtnComponent = PrimitiveComponent<'button'>

export const MenuItem: BtnComponent = styled(Btn)`
text-align: ${TEXT_ALIGN_LEFT};
interface ButtonProps extends StyleProps {
/** optional isAlert boolean to turn the background red, only seen in ODD */
isAlert?: boolean
}
export const MenuItem = styled.button<ButtonProps>`
text-align: ${TYPOGRAPHY.textAlignLeft};
font-size: ${TYPOGRAPHY.fontSizeP};
background-color: ${COLORS.transparent};
color: ${COLORS.darkBlackEnabled};
padding: ${SPACING.spacing3} 0.75rem ${SPACING.spacing3} 0.75rem;
&:hover {
&:hover,
&:active {
background-color: ${COLORS.lightBlue};
}
&:disabled,
&.disabled {
&:disabled {
background-color: ${COLORS.transparent};
color: ${COLORS.black}${COLORS.opacity50HexCode};
}
@media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} {
align-items: ${ALIGN_CENTER};
text-align: ${TYPOGRAPHY.textAlignCenter};
font-size: ${TYPOGRAPHY.fontSize28};
background-color: ${({ isAlert }) =>
isAlert ? COLORS.errorEnabled : COLORS.transparent};
color: ${({ isAlert }) =>
isAlert ? COLORS.white : COLORS.darkBlackEnabled};
padding: 1.625rem 1.5rem;
height: 4.875rem;
line-height: ${TYPOGRAPHY.lineHeight36};
&:hover,
&:active {
background-color: ${({ isAlert }) =>
isAlert ? COLORS.errorEnabled : COLORS.darkBlack_twenty};
}
&:disabled {
background-color: ${({ isAlert }) =>
isAlert ? COLORS.errorEnabled : COLORS.transparent};
color: ${({ isAlert }) =>
isAlert ? COLORS.white : COLORS.darkBlack_sixty};
}
}
`
41 changes: 10 additions & 31 deletions app/src/atoms/MenuList/MenuList.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,27 @@
import * as React from 'react'
import { css } from 'styled-components'
import {
Flex,
TYPOGRAPHY,
COLORS,
TEXT_ALIGN_LEFT,
SPACING,
} from '@opentrons/components'
import { MenuList } from './index'
import { MenuItem } from './MenuItem'

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

export default {
title: 'App/Atoms/MenuList',
component: MenuList,
onClick: { action: 'clicked' },
} as Meta

const Template: Story<React.ComponentProps<typeof MenuList>> = args => (
<MenuList {...args} />
)

const style = css`
width: auto;
text-align: ${TEXT_ALIGN_LEFT};
font-size: ${TYPOGRAPHY.fontSizeP};
padding-bottom: ${TYPOGRAPHY.fontSizeH6};
background-color: transparent;
color: ${COLORS.darkBlackEnabled};
padding-left: ${TYPOGRAPHY.fontSizeLabel};
padding-right: ${TYPOGRAPHY.fontSizeLabel};
padding-top: ${SPACING.spacing3};
&:hover {
background-color: ${COLORS.lightBlue};
}
&:disabled,
&.disabled {
color: ${COLORS.darkGreyDisabled};
}
`
const btn = <Flex css={style}>{'Example menu btn'}</Flex>

const menuBtn = 'example menu btn'
export const Primary = Template.bind({})
Primary.args = {
buttons: [btn, btn],
children: (
<>
<MenuItem>{menuBtn}</MenuItem>
<MenuItem>{menuBtn}</MenuItem>
<MenuItem>{menuBtn}</MenuItem>
</>
),
}
14 changes: 12 additions & 2 deletions app/src/atoms/MenuList/__tests__/MenuList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,22 @@ describe('MenuList', () => {
let props: React.ComponentProps<typeof MenuList>
beforeEach(() => {
props = {
buttons: [mockBtn],
children: mockBtn,
}
})

it('renders a child', () => {
it('renders a child not on device', () => {
const { getByText } = render(props)
getByText('mockBtn')
})
it('renders isOnDevice child, clicking background overlay calls onClick', () => {
props = {
...props,
isOnDevice: true,
onClick: jest.fn(),
}
const { getByLabelText } = render(props)
getByLabelText('BackgroundOverlay_ModalShell').click()
expect(props.onClick).toHaveBeenCalled()
})
})
29 changes: 25 additions & 4 deletions app/src/atoms/MenuList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,37 @@ import {
COLORS,
POSITION_ABSOLUTE,
DIRECTION_COLUMN,
ButtonProps,
Flex,
SPACING,
BORDERS,
JUSTIFY_CENTER,
} from '@opentrons/components'
import { ModalShell } from '../../molecules/Modal'

interface MenuListProps {
buttons: Array<ButtonProps | null | undefined>
children: React.ReactNode
isOnDevice?: boolean
onClick?: React.MouseEventHandler
}

export const MenuList = (props: MenuListProps): JSX.Element | null => {
return (
const { children, isOnDevice = false, onClick = null } = props
return isOnDevice && onClick != null ? (
<ModalShell
borderRadius={BORDERS.size_three}
width="18.0625rem"
onOutsideClick={onClick}
isOnDeviceDisplay
>
<Flex
boxShadow={BORDERS.shadowSmall}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_CENTER}
>
{children}
</Flex>
</ModalShell>
) : (
<Flex
borderRadius="4px 4px 0px 0px"
zIndex={10}
Expand All @@ -23,8 +43,9 @@ export const MenuList = (props: MenuListProps): JSX.Element | null => {
top="2.6rem"
right={`calc(50% + ${String(SPACING.spacing2)})`}
flexDirection={DIRECTION_COLUMN}
width="max-content"
>
{props.buttons}
{children}
</Flex>
)
}
42 changes: 20 additions & 22 deletions app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,26 @@ export const ModuleOverflowMenu = (

return (
<Flex position={POSITION_RELATIVE}>
<MenuList
buttons={[
menuOverflowItemsByModuleType[module.moduleType].map(
(item: any, index: number) => {
return (
<React.Fragment key={`${index}_${String(module.moduleType)}`}>
<MenuItem
key={`${index}_${String(module.moduleModel)}`}
onClick={() => item.onClick(item.isSecondary)}
data-testid={`module_setting_${String(module.moduleModel)}`}
disabled={item.disabledReason || isDisabled}
whiteSpace="nowrap"
>
{item.setSetting}
</MenuItem>
{item.menuButtons}
</React.Fragment>
)
}
),
]}
/>
<MenuList>
{menuOverflowItemsByModuleType[module.moduleType].map(
(item: any, index: number) => {
return (
<React.Fragment key={`${index}_${String(module.moduleType)}`}>
<MenuItem
key={`${index}_${String(module.moduleModel)}`}
onClick={() => item.onClick(item.isSecondary)}
data-testid={`module_setting_${String(module.moduleModel)}`}
disabled={item.disabledReason || isDisabled}
whiteSpace="nowrap"
>
{item.setSetting}
</MenuItem>
{item.menuButtons}
</React.Fragment>
)
}
)}
</MenuList>
</Flex>
)
}
Loading

0 comments on commit 066e13e

Please sign in to comment.