Skip to content

Commit

Permalink
fix: modal regressions (#636)
Browse files Browse the repository at this point in the history
jsladerman authored Aug 21, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 8592fab commit d55d588
Showing 3 changed files with 60 additions and 52 deletions.
9 changes: 3 additions & 6 deletions src/components/IconFrame.tsx
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ type IconFrameProps = {
type?: Type
selected?: boolean
background?: SemanticColorKey
}
} & Omit<ComponentProps<typeof IconFrameSC>, 'size'>

const IconFrameSC = styled(Flex)<{
$type: Type
@@ -148,10 +148,7 @@ const IconFrameSC = styled(Flex)<{
...($type === 'floating' ? { boxShadow: theme.boxShadows.slight } : {}),
}))

const IconFrame = forwardRef<
HTMLDivElement,
IconFrameProps & ComponentProps<typeof IconFrameSC>
>(
const IconFrame = forwardRef(
(
{
icon,
@@ -166,7 +163,7 @@ const IconFrame = forwardRef<
background,
as,
...props
},
}: IconFrameProps,
ref
) => {
icon = cloneElement(icon, { size: sizeToIconSize[size] })
34 changes: 27 additions & 7 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -8,7 +8,10 @@ import {
useEffect,
} from 'react'

import styled, { type StyledComponentPropsWithRef } from 'styled-components'
import styled, {
type StyledComponentPropsWithRef,
useTheme,
} from 'styled-components'

import { type ColorKey, type Nullable, type SeverityExt } from '../types'

@@ -28,7 +31,7 @@ export const SEVERITIES = [
'success',
'danger',
] as const satisfies Readonly<SeverityExt[]>
const SIZES = ['medium', 'large', 'custom'] as const
const SIZES = ['medium', 'large', 'custom', 'auto'] as const

type ModalSeverity = Extract<SeverityExt, (typeof SEVERITIES)[number]>

@@ -37,6 +40,7 @@ type ModalSize = (typeof SIZES)[number]
type ModalPropsType = ModalWrapperProps & {
onClose?: Nullable<() => void>
form?: boolean
scrollable?: boolean
size?: ModalSize
header?: ReactNode
actions?: ReactNode
@@ -68,24 +72,32 @@ const severityToIcon = {
const sizeToWidth = {
medium: 480,
large: 608,
auto: 'auto',
custom: undefined as undefined,
} as const satisfies Record<ModalSize, number | undefined>
} as const satisfies Partial<Record<ModalSize, number | string | undefined>>

const ModalSC = styled(Card)<{
$width: number
$maxWidth: number
}>(({ theme, $width, $maxWidth }) => ({
position: 'relative',
display: 'flex',
flexDirection: 'column',
height: '100%',
width: $width,
maxWidth: $maxWidth,
backgroundColor: theme.colors['fill-one'],
}))

const ModalContentSC = styled.div<{
$scrollable: boolean
$hasActions: boolean
}>(({ theme, $hasActions }) => ({
}>(({ theme, $scrollable, $hasActions }) => ({
position: 'relative',
zIndex: 0,
display: 'flex',
flexDirection: 'column',
overflow: $scrollable ? 'auto' : 'hidden',
margin: theme.spacing.large,
marginBottom: $hasActions ? 0 : theme.spacing.large,
...theme.partials.text.body1,
@@ -144,6 +156,7 @@ function ModalRef(
}: ModalPropsType,
ref: Ref<any>
) {
const theme = useTheme()
const HeaderIcon = severityToIcon[severity ?? 'default']
const iconColorKey = severityToIconColorKey[severity ?? 'default']

@@ -160,21 +173,28 @@ function ModalRef(
[onClose]
)

const maxWidth =
size === 'auto'
? `min(1000px, 100vw - ${theme.spacing.xlarge * 2}px)`
: sizeToWidth[size]

return (
<ModalWrapper
ref={ref}
open={open}
onOpenChange={triggerClose}
scrollable={scrollable}
{...props}
>
<ModalSC
forwardedAs={asForm ? 'form' : undefined}
$width={sizeToWidth[size]}
$maxWidth={sizeToWidth[size]}
$maxWidth={maxWidth}
{...(asForm ? formProps : {})}
>
<ModalContentSC $hasActions={!!actions}>
<ModalContentSC
$scrollable={scrollable}
$hasActions={!!actions}
>
{!!header && (
<ModalHeaderWrapSC ref={ref}>
{HeaderIcon && (
69 changes: 30 additions & 39 deletions src/components/ModalWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
// styling here mostly just for the overlay and animations
import * as Dialog from '@radix-ui/react-dialog'

import { type ComponentProps, type ReactNode, forwardRef } from 'react'
import { type ReactNode, forwardRef } from 'react'
import styled, { useTheme } from 'styled-components'

const ANIMATION_SPEED = '150ms'

export type ModalWrapperProps = {
open: boolean
onOpenChange?: (open: boolean) => void
scrollable?: boolean
children?: ReactNode
} & ComponentProps<'div'>
} & Dialog.DialogContentProps

function ModalWrapperRef(
{
open,
onOpenChange,
scrollable = true,
children,
...props
}: ModalWrapperProps,
{ open, onOpenChange, children, ...props }: ModalWrapperProps,
ref: any
) {
const theme = useTheme()
@@ -32,10 +25,9 @@ function ModalWrapperRef(
onOpenChange={onOpenChange}
>
<Dialog.Portal container={portalElement}>
<OverlaySC>
<OverlaySC onClick={(e) => e.stopPropagation()}>
<ContentSC
ref={ref}
$scrollable={scrollable}
{...props}
>
{children}
@@ -46,36 +38,35 @@ function ModalWrapperRef(
)
}

const ContentSC = styled(Dialog.Content)<{ $scrollable?: boolean }>(
({ $scrollable }) => ({
overflowY: $scrollable ? 'auto' : 'hidden',
maxHeight: '100%',
'@keyframes popIn': {
from: { transform: 'scale(0.8)' },
to: { transform: 'scale(1)' },
},
'@keyframes popOut': {
from: { transform: 'scale(1)' },
to: { transform: 'scale(0.9)' },
},
'&[data-state="open"]': {
animation: `popIn ${ANIMATION_SPEED} ease-out`,
},
'&[data-state="closed"]': {
animation: `popOut ${ANIMATION_SPEED} ease-out`,
},
})
)
const ContentSC = styled(Dialog.Content)({
display: 'flex',
flexDirection: 'column',
overflow: 'auto',
'@keyframes popIn': {
from: { transform: 'scale(0.8)' },
to: { transform: 'scale(1)' },
},
'@keyframes popOut': {
from: { transform: 'scale(1)' },
to: { transform: 'scale(0.9)' },
},
'&[data-state="open"]': {
animation: `popIn ${ANIMATION_SPEED} ease-out`,
},
'&[data-state="closed"]': {
animation: `popOut ${ANIMATION_SPEED} ease-out`,
},
})

const OverlaySC = styled(Dialog.Overlay)(({ theme }) => ({
background: theme.colors['modal-backdrop'],
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
position: 'fixed',
inset: 0,
background: theme.colors['modal-backdrop'],
padding: theme.spacing.xlarge,
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'grid',
placeItems: 'center',
zIndex: theme.zIndexes.modal,
'@keyframes fadeIn': {
from: { opacity: 0 },

0 comments on commit d55d588

Please sign in to comment.