feat: start over and layout
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { css } from '@/styled-system/css'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { type FC, type ReactNode } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
export interface BackDropProps {
|
||||
children?: ReactNode
|
||||
isOpen: boolean
|
||||
onClickAway: () => void
|
||||
}
|
||||
|
||||
const BackDrop: FC<BackDropProps> = ({ isOpen, onClickAway, children }) => {
|
||||
if (typeof window === 'undefined') return null
|
||||
return createPortal((
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
className={css({
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 'modalBackdrop',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)'
|
||||
})}
|
||||
onClick={(event) => {
|
||||
if (event.target === event.currentTarget) {
|
||||
onClickAway()
|
||||
}
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
), document.body)
|
||||
}
|
||||
export default BackDrop
|
||||
@@ -0,0 +1,59 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { typography, type TypographyVariantProps } from '@/styled-system/recipes'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import React, { type ElementType, type FC } from 'react'
|
||||
|
||||
type ComposedTypographyProps = MergeOmitting<React.HTMLAttributes<HTMLElement>, TypographyVariantProps>
|
||||
|
||||
export interface TypographyProps extends ComposedTypographyProps {
|
||||
component?: ElementType
|
||||
}
|
||||
|
||||
const variantToComponent = (variant: TypographyVariantProps['variant']): ElementType => {
|
||||
switch (variant) {
|
||||
case 'h1':
|
||||
case 'h2':
|
||||
case 'h3':
|
||||
case 'h4':
|
||||
case 'h5':
|
||||
case 'h6':
|
||||
return variant
|
||||
case 'subtitle1':
|
||||
case 'subtitle2':
|
||||
return 'div'
|
||||
case 'button':
|
||||
case 'overline':
|
||||
case 'srOnly':
|
||||
case 'caption':
|
||||
return 'span'
|
||||
case 'body1':
|
||||
case 'body2':
|
||||
default:
|
||||
return 'p'
|
||||
}
|
||||
}
|
||||
|
||||
const isHeading = (text: string): boolean => {
|
||||
return text.startsWith('h')
|
||||
}
|
||||
|
||||
const Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
|
||||
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
||||
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
typographyRecipeArgs.color = typographyRecipeArgs.color !== undefined
|
||||
? typographyRecipeArgs.color
|
||||
: typeof typographyRecipeArgs.variant === 'string' && isHeading(typographyRecipeArgs.variant)
|
||||
? 'primary'
|
||||
: undefined
|
||||
return (
|
||||
<Component
|
||||
className={cx(typography(typographyRecipeArgs), className)}
|
||||
{...allOtherTypographyProps}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
)
|
||||
}
|
||||
|
||||
export default Typography
|
||||
Reference in New Issue
Block a user