hensei-web/components/DialogContent/index.tsx

105 lines
2.8 KiB
TypeScript

import React, { useEffect } from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import classNames from 'classnames'
import { DialogClose, DialogTitle } from '~components/Dialog'
import Overlay from '~components/Overlay'
import CrossIcon from '~public/icons/Cross.svg'
import './index.scss'
interface Props
extends React.DetailedHTMLProps<
React.DialogHTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {
header?: React.ReactNode
title?: string
onEscapeKeyDown: (event: KeyboardEvent) => void
onOpenAutoFocus: (event: Event) => void
}
const DialogContent = React.forwardRef<HTMLDivElement, Props>(function dialog(
{ children, ...props },
forwardedRef
) {
// Classes
const classes = classNames(props.className, {
DialogContent: true,
})
// Refs
const headerRef = React.createRef<HTMLDivElement>()
const containerRef = React.createRef<HTMLDivElement>()
// Elements
const genericHeader = (
<div className="DialogHeader" ref={headerRef}>
<DialogTitle className="DialogTitle">
{props.title ? props.title : ''}
</DialogTitle>
<DialogClose className="DialogClose" asChild>
<span>
<CrossIcon />
</span>
</DialogClose>
</div>
)
// Handlers
function handleScroll(event: React.UIEvent<HTMLDivElement, UIEvent>) {
const headerElement = headerRef.current
const scrollTop = event.currentTarget?.scrollTop
const boxShadowBase = '0 2px 8px'
const maxValue = 50
if (headerElement && scrollTop >= 0) {
const input = scrollTop > maxValue ? maxValue : scrollTop
const boxShadowOpacity = mapRange(input, 0, maxValue, 0.0, 0.16)
const borderOpacity = mapRange(input, 0, maxValue, 0.0, 0.24)
console.log(
`Scroll top: ${scrollTop}, interpolated opacity: ${boxShadowOpacity}`
)
headerElement.style.boxShadow = `${boxShadowBase} rgba(0, 0, 0, ${boxShadowOpacity})`
headerElement.style.borderBottomColor = `rgba(0, 0, 0, ${borderOpacity})`
}
}
function mapRange(
value: number,
low1: number,
high1: number,
low2: number,
high2: number
) {
return low2 + ((high2 - low2) * (value - low1)) / (high1 - low1)
}
return (
<DialogPrimitive.Portal>
<dialog className="Dialog">
<DialogPrimitive.Content
{...props}
className={classes}
onOpenAutoFocus={props.onOpenAutoFocus}
onEscapeKeyDown={props.onEscapeKeyDown}
ref={forwardedRef}
>
{props.title ? genericHeader : ''}
<div
className="Scrollable"
ref={containerRef}
onScroll={handleScroll}
>
{children}
</div>
</DialogPrimitive.Content>
</dialog>
<Overlay visible={true} open={true} />
</DialogPrimitive.Portal>
)
})
export default DialogContent