learnhouse/apps/web/components/StyledElements/Modal/Modal.tsx

159 lines
No EOL
4.5 KiB
TypeScript

'use client';
import React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { styled, keyframes } from '@stitches/react';
import { violet, blackA, mauve, green } from '@radix-ui/colors';
import { ButtonBlack } from '../Form/Form';
type ModalParams = {
dialogTitle: string;
dialogDescription: string;
dialogContent: React.ReactNode;
dialogClose?: React.ReactNode | null;
dialogTrigger?: React.ReactNode;
addDefCloseButton?: boolean;
onOpenChange: any;
isDialogOpen?: boolean;
minHeight?: "sm" | "md" | "lg" | "xl" | "no-min";
};
const Modal = (params: ModalParams) => (
<Dialog.Root open={params.isDialogOpen} onOpenChange={params.onOpenChange}>
{params.dialogTrigger ? (
<Dialog.Trigger asChild>
{params.dialogTrigger}
</Dialog.Trigger>
) : null}
<Dialog.Portal>
<DialogOverlay />
<DialogContent minHeight={params.minHeight}>
<DialogTopBar className='-space-y-1'>
<DialogTitle>{params.dialogTitle}</DialogTitle>
<DialogDescription>
{params.dialogDescription}
</DialogDescription>
</DialogTopBar>
{params.dialogContent}
{params.dialogClose ? (
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
<Dialog.Close asChild>
{params.dialogClose}
</Dialog.Close>
</Flex>
) : null}
{params.addDefCloseButton ? (
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
<Dialog.Close asChild>
<ButtonBlack type="submit" css={{ marginTop: 10 }}>Close</ButtonBlack>
</Dialog.Close>
</Flex>
) : null}
</DialogContent>
</Dialog.Portal>
</Dialog.Root>
);
const overlayShow = keyframes({
'0%': { opacity: 0 },
'100%': { opacity: 1 },
});
const overlayClose = keyframes({
'0%': { opacity: 1 },
'100%': { opacity: 0 },
});
const contentShow = keyframes({
'0%': { opacity: 0, transform: 'translate(-50%, -50%) scale(.96)' },
'100%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' },
});
const contentClose = keyframes({
'0%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' },
'100%': { opacity: 0, transform: 'translate(-50%, -52%) scale(.96)' },
});
const DialogOverlay = styled(Dialog.Overlay, {
backgroundColor: blackA.blackA9,
position: 'fixed',
zIndex: 500,
inset: 0,
animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
'&[data-state="closed"]': {
animation: `${overlayClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
},
});
const DialogContent = styled(Dialog.Content, {
variants: {
minHeight: {
'no-min': {
minHeight: '0px',
},
'sm': {
minHeight: '300px',
},
'md': {
minHeight: '500px',
},
'lg': {
minHeight: '700px',
},
'xl': {
minHeight: '900px',
},
},
},
backgroundColor: 'white',
borderRadius: 18,
zIndex: 501,
boxShadow: 'hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px',
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '90vw',
overflow: 'hidden',
maxHeight: '85vh',
minHeight: '300px',
maxWidth: '600px',
padding: 11,
animation: `${contentShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
'&:focus': { outline: 'none' },
'&[data-state="closed"]': {
animation: `${contentClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
},
transition: "max-height 0.3s ease-out",
});
const DialogTopBar = styled('div', {
background: "#F7F7F7",
padding: "8px 14px ",
borderRadius: 14,
});
const DialogTitle = styled(Dialog.Title, {
margin: 0,
fontWeight: 700,
letterSpacing: "-0.05em",
padding: 0,
color: mauve.mauve12,
fontSize: 21,
});
const DialogDescription = styled(Dialog.Description, {
color: mauve.mauve11,
letterSpacing: "-0.03em",
fontSize: 15,
padding: 0,
margin: 0,
});
const Flex = styled('div', { display: 'flex' });
export default Modal;