feat: create new dialog component using radix-ui primitives
This commit is contained in:
parent
5f0ffbf6dc
commit
67b9c43ae1
3 changed files with 105 additions and 0 deletions
36
src/client/components/ui/Dialog/Dialog.module.scss
Normal file
36
src/client/components/ui/Dialog/Dialog.module.scss
Normal file
|
@ -0,0 +1,36 @@
|
|||
@keyframes zoomIn {
|
||||
0% {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dimmedBackground {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.dimmedBackground {
|
||||
animation-name: dimmedBackground;
|
||||
animation-duration: 0.2s;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.zoomIn {
|
||||
animation-name: zoomIn;
|
||||
animation-duration: 0.25s;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: spring;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
68
src/client/components/ui/Dialog/Dialog.tsx
Normal file
68
src/client/components/ui/Dialog/Dialog.tsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import clsx from 'clsx';
|
||||
import styles from './Dialog.module.scss';
|
||||
|
||||
type Sizes = 'sm' | 'md' | 'lg' | 'xl';
|
||||
type ModalType = 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger';
|
||||
|
||||
type ModalProps = {
|
||||
size?: Sizes;
|
||||
type?: ModalType;
|
||||
};
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogPortal = ({ className, children, ...props }: DialogPrimitive.DialogPortalProps & ModalProps) => (
|
||||
<DialogPrimitive.Portal className={clsx(className)} {...props}>
|
||||
<div className={clsx('modal modal-sm d-block', styles.dimmedBackground)}>
|
||||
<div className={clsx(`modal-dialog modal-dialog-centered modal-${props.size || 'lg'}`, styles.zoomIn)}>
|
||||
<div className="shadow modal-content">
|
||||
<DialogPrimitive.Close className="btn-close mt-1">
|
||||
<button data-testid="modal-close-button" type="button" className="btn-close" aria-label="Close" />
|
||||
</DialogPrimitive.Close>
|
||||
<div data-testid="modal-status" className={clsx('modal-status', { [`bg-${props.type}`]: Boolean(props.type), 'd-none': !props.type })} />
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogPrimitive.Portal>
|
||||
);
|
||||
DialogPortal.displayName = DialogPrimitive.Portal.displayName;
|
||||
|
||||
const DialogOverlay = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>>(({ className, children, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay className={clsx('', className)} {...props} ref={ref} />
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & ModalProps>(
|
||||
({ className, children, ...props }, ref) => (
|
||||
<DialogPortal type={props.type} size={props.size}>
|
||||
<DialogPrimitive.Content ref={ref} className={clsx('modal-content mt-1', className)} {...props}>
|
||||
{children}
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
),
|
||||
);
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => <div data-testid="modal-header" className={clsx('modal-header', className)} {...props} />;
|
||||
DialogHeader.displayName = 'DialogHeader';
|
||||
|
||||
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => <div className={clsx('modal-footer', className)} {...props} />;
|
||||
DialogFooter.displayName = 'DialogFooter';
|
||||
|
||||
const DialogTitle = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Title>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title ref={ref} className={clsx('modal-title', className)} {...props} />
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Description>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description ref={ref} className={clsx('modal-body', className)} {...props} />
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };
|
1
src/client/components/ui/Dialog/index.ts
Normal file
1
src/client/components/ui/Dialog/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { Dialog, DialogTitle, DialogFooter, DialogHeader, DialogContent, DialogTrigger, DialogDescription } from './Dialog';
|
Loading…
Add table
Reference in a new issue