mirror of https://github.com/buster-so/buster.git
106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
import React, { useMemo } from 'react';
|
|
import { type ButtonProps, Button } from '../buttons/Button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle
|
|
} from './ModalBase';
|
|
import { useMemoizedFn } from '@/hooks';
|
|
import { cn } from '@/lib/classMerge';
|
|
|
|
export interface ModalProps {
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
open: boolean;
|
|
onClose: () => void;
|
|
footer: {
|
|
left?: React.ReactNode;
|
|
primaryButton: {
|
|
text: string;
|
|
onClick: () => void;
|
|
variant?: ButtonProps['variant'];
|
|
loading?: boolean;
|
|
disabled?: boolean;
|
|
};
|
|
secondaryButton?: {
|
|
text: string;
|
|
onClick: () => void;
|
|
variant?: ButtonProps['variant'];
|
|
loading?: boolean;
|
|
disabled?: boolean;
|
|
};
|
|
};
|
|
header: {
|
|
title: React.ReactNode;
|
|
description?: React.ReactNode;
|
|
};
|
|
width?: number;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
export const AppModal: React.FC<ModalProps> = React.memo(
|
|
({ open, onClose, footer, header, width = 600, className, style, children }) => {
|
|
const onOpenChange = useMemoizedFn((open: boolean) => {
|
|
if (!open) {
|
|
onClose();
|
|
}
|
|
});
|
|
|
|
const memoizedStyle = useMemo(
|
|
() => ({
|
|
minWidth: width ?? 600,
|
|
maxWidth: width ?? 600,
|
|
...style
|
|
}),
|
|
[width, style]
|
|
);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className={className} style={memoizedStyle}>
|
|
<div className="flex flex-col gap-4 p-6">
|
|
{header && (
|
|
<DialogHeader>
|
|
{header.title && <DialogTitle>{header.title}</DialogTitle>}
|
|
{header.description && <DialogDescription>{header.description}</DialogDescription>}
|
|
</DialogHeader>
|
|
)}
|
|
|
|
{children}
|
|
</div>
|
|
|
|
{footer && (
|
|
<DialogFooter
|
|
className={cn('flex items-center', footer.left ? 'justify-between' : 'justify-end')}>
|
|
{footer.left && footer.left}
|
|
<div className={cn('flex items-center space-x-2')}>
|
|
{footer.secondaryButton && (
|
|
<Button
|
|
onClick={footer.secondaryButton.onClick}
|
|
variant={footer.secondaryButton.variant ?? 'ghost'}
|
|
loading={footer.secondaryButton.loading}
|
|
disabled={footer.secondaryButton.disabled}>
|
|
{footer.secondaryButton.text}
|
|
</Button>
|
|
)}
|
|
<Button
|
|
onClick={footer.primaryButton.onClick}
|
|
variant={footer.primaryButton.variant ?? 'black'}
|
|
loading={footer.primaryButton.loading}
|
|
disabled={footer.primaryButton.disabled}>
|
|
{footer.primaryButton.text}
|
|
</Button>
|
|
</div>
|
|
</DialogFooter>
|
|
)}
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
);
|
|
|
|
AppModal.displayName = 'AppModal';
|