123 lines
3.9 KiB
JavaScript
123 lines
3.9 KiB
JavaScript
import React from 'react';
|
|
import { Dialog } from '@headlessui/react';
|
|
import { Cancel01Icon } from '../icons/index.js';
|
|
import Button from './Button.js';
|
|
|
|
const FORM_ID = 'modal-form-inner';
|
|
|
|
const Modal = ({
|
|
isOpen = true,
|
|
onClose,
|
|
title,
|
|
children,
|
|
footer,
|
|
size = 'lg',
|
|
closable = true,
|
|
// Form props — when provided, wraps children in a <form> and shows a standard footer
|
|
onSubmit,
|
|
submitLabel = 'Enregistrer',
|
|
cancelLabel = 'Annuler',
|
|
submitVariant = 'primary',
|
|
loading = false,
|
|
disabled = false,
|
|
}) => {
|
|
const sizeClasses = {
|
|
sm: 'max-w-md',
|
|
md: 'max-w-lg',
|
|
lg: 'max-w-2xl',
|
|
xl: 'max-w-4xl',
|
|
full: 'max-w-7xl',
|
|
};
|
|
|
|
const isForm = typeof onSubmit === 'function';
|
|
|
|
const handleFormSubmit = (e) => {
|
|
e.preventDefault();
|
|
onSubmit(e);
|
|
};
|
|
|
|
const resolvedFooter = footer ?? (isForm ? (
|
|
<div className="flex items-center justify-end gap-2">
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={onClose}
|
|
disabled={loading}
|
|
>
|
|
{cancelLabel}
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
form={FORM_ID}
|
|
variant={submitVariant}
|
|
size="sm"
|
|
loading={loading}
|
|
disabled={disabled || loading}
|
|
>
|
|
{submitLabel}
|
|
</Button>
|
|
</div>
|
|
) : null);
|
|
|
|
return (
|
|
<Dialog
|
|
open={isOpen}
|
|
onClose={closable ? onClose : () => {}}
|
|
className="relative z-50"
|
|
>
|
|
{/* Backdrop */}
|
|
<div className="fixed inset-0 bg-black/35 backdrop-blur-[2px]" aria-hidden="true" />
|
|
|
|
{/* Container */}
|
|
<div className="fixed inset-0 flex items-center justify-center p-4">
|
|
<Dialog.Panel
|
|
className={`
|
|
w-full ${sizeClasses[size]}
|
|
bg-white dark:bg-[#0B0B0B]
|
|
border border-neutral-200 dark:border-neutral-800
|
|
rounded-lg
|
|
shadow-xl
|
|
max-h-[90vh]
|
|
overflow-hidden
|
|
flex flex-col
|
|
`}
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between px-4 py-3 border-b border-neutral-200 dark:border-neutral-800">
|
|
<Dialog.Title className="text-sm font-medium text-neutral-900 dark:text-white">
|
|
{title}
|
|
</Dialog.Title>
|
|
{closable && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={onClose}
|
|
icon={<Cancel01Icon className="w-4 h-4" />}
|
|
className="!p-1 -mr-1"
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex-1 overflow-y-auto p-4">
|
|
{isForm ? (
|
|
<form id={FORM_ID} onSubmit={handleFormSubmit} noValidate>
|
|
{children}
|
|
</form>
|
|
) : children}
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
{resolvedFooter && (
|
|
<div className="px-4 py-3 border-t border-neutral-200 dark:border-neutral-800 bg-neutral-50 dark:bg-[#0B0B0B]">
|
|
{resolvedFooter}
|
|
</div>
|
|
)}
|
|
</Dialog.Panel>
|
|
</div>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
export default Modal;
|