Skip to content

Commit

Permalink
feat(app): update modal component and labware liquid modal (#11216)
Browse files Browse the repository at this point in the history
fix #11142
  • Loading branch information
smb2268 authored Jul 29, 2022
1 parent 831aeae commit 3bd4b3a
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 11 deletions.
78 changes: 78 additions & 0 deletions app/src/atoms/Modal/ModalHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from 'react'
import { css } from 'styled-components'
import {
Btn,
Icon,
TYPOGRAPHY,
Flex,
ALIGN_CENTER,
JUSTIFY_SPACE_BETWEEN,
SPACING,
JUSTIFY_CENTER,
} 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: ${JUSTIFY_CENTER};
align-items: ${ALIGN_CENTER};
border-radius: 0.875rem;
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>
)
}
9 changes: 6 additions & 3 deletions app/src/atoms/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ import {

import { StyledText } from '../text'
import { Divider } from '../structure'

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 +57,7 @@ export const Modal = (props: ModalProps): JSX.Element => {
children,
maxHeight,
} = props
const header =
const defaultHeader =
title != null ? (
<>
<Flex
Expand Down Expand Up @@ -100,7 +103,7 @@ export const Modal = (props: ModalProps): JSX.Element => {
<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,17 @@ 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
paddingX={SPACING.spacing4}
paddingTop={SPACING.spacing4}
backgroundColor={COLORS.lightGrey}
>
<Flex flexDirection={DIRECTION_ROW} gridGap={SPACING.spacing3}>
<Flex
flexDirection={DIRECTION_COLUMN}
Expand Down Expand Up @@ -181,6 +184,6 @@ export const LiquidsLabwareDetailsModal = (
</Flex>
</Flex>
</Box>
</Modal>
</ModalShell>
)
}

0 comments on commit 3bd4b3a

Please sign in to comment.