Skip to content

Commit

Permalink
feat(app): update modal component and labware liquid modal
Browse files Browse the repository at this point in the history
fix #11142
  • Loading branch information
smb2268 committed Jul 27, 2022
1 parent 0115066 commit 937eb00
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 12 deletions.
77 changes: 77 additions & 0 deletions app/src/atoms/Modal/ModalHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import * as React from 'react'
import { css } from 'styled-components'
import {
Btn,
Icon,
TYPOGRAPHY,
Flex,
ALIGN_CENTER,
JUSTIFY_SPACE_BETWEEN,
SPACING,
} from '@opentrons/components'

import { StyledText } from '../text'
import { Divider } from '../structure'
import type { IconProps } from '@opentrons/components'

export interface ModalHeaderProps {
onClose?: React.MouseEventHandler
title: React.ReactNode
icon?: IconProps
closeButton?: JSX.Element
}

const closeIconStyles = css`
display: flex;
justify-content: center;
align-items: center;
border-radius: 14px;
width: ${SPACING.spacingL};
height: ${SPACING.spacingL};
&:hover {
background-color: #16212d26;
}
&:active {
background-color: #16212d40;
}
`

export const ModalHeader = (props: ModalHeaderProps): JSX.Element => {
const { icon, onClose, title, closeButton } = props
return (
<>
<Flex
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_SPACE_BETWEEN}
paddingX={SPACING.spacing5}
paddingY={SPACING.spacing4}
>
<Flex>
{icon != null && <Icon {...icon} />}
<StyledText as="h3" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{title}
</StyledText>
</Flex>
{closeButton != null
? { closeButton }
: onClose != null && (
<Btn
onClick={onClose}
css={closeIconStyles}
data-testid={`ModalHeader_icon_close_${
typeof title === 'string' ? title : ''
}`}
>
<Icon
name={'close'}
width={SPACING.spacing5}
height={SPACING.spacing5}
/>
</Btn>
)}
</Flex>
<Divider width="100%" marginY="0" />
</>
)
}
116 changes: 116 additions & 0 deletions app/src/atoms/Modal/ModalShell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import * as React from 'react'

import {
Box,
Flex,
StyleProps,
COLORS,
SPACING,
POSITION_FIXED,
POSITION_ABSOLUTE,
ALIGN_CENTER,
JUSTIFY_CENTER,
POSITION_RELATIVE,
OVERFLOW_AUTO,
POSITION_STICKY,
BORDERS,
} from '@opentrons/components'

const BASE_STYLE = {
position: POSITION_ABSOLUTE,
alignItems: ALIGN_CENTER,
justifyContent: JUSTIFY_CENTER,
top: 0,
right: 0,
bottom: 0,
left: 0,
width: '100%',
height: '100%',
} as const

const MODAL_STYLE = {
backgroundColor: COLORS.white,
position: POSITION_RELATIVE,
overflowY: OVERFLOW_AUTO,
maxHeight: '100%',
width: '100%',
margin: SPACING.spacing5,
borderRadius: BORDERS.radiusSoftCorners,
boxShadow: BORDERS.smallDropShadow,
} as const

const HEADER_STYLE = {
backgroundColor: COLORS.white,
position: POSITION_STICKY,
top: 0,
} as const

const FOOTER_STYLE = {
backgroundColor: COLORS.white,
position: POSITION_STICKY,
bottom: 0,
boxShadow: '0px 3px 6px 0px #0000003B',
} as const

export interface ModalShellProps extends StyleProps {
/** Optional close on outside click **/
onOutsideClick?: React.MouseEventHandler
/** Optional sticky header */
header?: React.ReactNode
/** Optional sticky footer */
footer?: React.ReactNode
/** Modal content */
children: React.ReactNode
}

/**
* A ModalShell is a layout component for building more specific modals.
*
* It includes:
* - An overlay
* - A content area, with `overflow-y: auto` and customizable with style props
* - An optional sticky header
* - An optional sticky footer
* - An optional onOutsideClick function
*/
export function ModalShell(props: ModalShellProps): JSX.Element {
const {
onOutsideClick,
zIndex = 10,
header,
footer,
children,
...styleProps
} = props

return (
<Flex
position={POSITION_FIXED}
left="0"
right="0"
top="0"
bottom="0"
zIndex="1"
backgroundColor={COLORS.backgroundOverlay}
cursor="default"
onClick={e => {
e.stopPropagation()
if (onOutsideClick != null) onOutsideClick(e)
}}
>
<Flex {...BASE_STYLE} zIndex={zIndex}>
<Box
{...MODAL_STYLE}
{...styleProps}
onClick={e => {
e.stopPropagation()
}}
>
{header != null ? <Box {...HEADER_STYLE}>{header}</Box> : null}
<Box>{children}</Box>
{footer != null ? <Box {...FOOTER_STYLE}>{footer}</Box> : null}
</Box>
</Flex>
</Flex>
)
}
49 changes: 45 additions & 4 deletions app/src/atoms/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { css } from 'styled-components'
import {
Btn,
Icon,
Box,
BaseModal,
BaseModalProps,
TYPOGRAPHY,
Expand All @@ -14,17 +15,23 @@ import {
BORDERS,
} from '@opentrons/components'

import { useFeatureFlag } from '../../redux/config'
import { StyledText } from '../text'
import { Divider } from '../structure'

import { ModalShell } from './ModalShell'
import { ModalHeader } from './ModalHeader'
import type { IconProps } from '@opentrons/components'

type ModalType = 'info' | 'warning' | 'error'
export * from './ModalShell'
export * from './ModalHeader'

export interface ModalProps extends BaseModalProps {
type?: ModalType
onClose?: React.MouseEventHandler
closeOnOutsideClick?: boolean
title?: React.ReactNode
footer?: React.ReactNode
children?: React.ReactNode
icon?: IconProps
}
Expand Down Expand Up @@ -54,7 +61,8 @@ export const Modal = (props: ModalProps): JSX.Element => {
children,
maxHeight,
} = props
const header =
const liquidSetupEnabled = useFeatureFlag('enableLiquidSetup')
const defaultHeader =
title != null ? (
<>
<Flex
Expand Down Expand Up @@ -95,12 +103,45 @@ export const Modal = (props: ModalProps): JSX.Element => {
<Divider width="100%" marginY="0" />
</>
) : null
const modalHeader = (
<ModalHeader
onClose={onClose}
title={title}
icon={
['error', 'warning'].includes(type)
? {
name: 'ot-alert',
color: type === 'error' ? COLORS.error : COLORS.warning,
size: SPACING.spacingM,
marginRight: SPACING.spacing3,
}
: undefined
}
/>
)

return (
return liquidSetupEnabled ? (
<ModalShell
width="31.25rem"
header={modalHeader}
onOutsideClick={closeOnOutsideClick ? onClose : undefined}
// center within viewport aside from nav
marginLeft="7.125rem"
{...props}
>
<Box
paddingTop={SPACING.spacing4}
paddingBottom={SPACING.spacing5}
paddingX={SPACING.spacing5}
>
{children}
</Box>
</ModalShell>
) : (
<BaseModal
width={props.width ? props.width : '31.25rem'}
noHeaderStyles
header={header}
header={defaultHeader}
css={css`
border-radius: ${BORDERS.radiusSoftCorners};
box-shadow: ${BORDERS.smallDropShadow};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
useProtocolDetailsForRun,
useLabwareRenderInfoForRunById,
} from '../../../Devices/hooks'
import { Modal } from '../../../../atoms/Modal'
import { ModalShell, ModalHeader } from '../../../../atoms/Modal'
import { StyledText } from '../../../../atoms/text'
import { LiquidDetailCard } from './LiquidDetailCard'
import {
Expand Down Expand Up @@ -76,14 +76,13 @@ export const LiquidsLabwareDetailsModal = (
}
`
return (
<Modal
onClose={closeModal}
title={labwareName}
closeOnOutsideClick
marginX={SPACING.spacing5}
<ModalShell
onOutsideClick={closeModal}
width="45rem"
marginLeft="7.125rem"
header={<ModalHeader onClose={closeModal} title={labwareName} />}
>
<Box>
<Box padding={SPACING.spacing4} backgroundColor={COLORS.lightGrey}>
<Flex flexDirection={DIRECTION_ROW} gridGap={SPACING.spacing3}>
<Flex
flexDirection={DIRECTION_COLUMN}
Expand Down Expand Up @@ -181,6 +180,6 @@ export const LiquidsLabwareDetailsModal = (
</Flex>
</Flex>
</Box>
</Modal>
</ModalShell>
)
}

0 comments on commit 937eb00

Please sign in to comment.