2023-12-13 14:32:57 +03:00
|
|
|
'use client';
|
|
|
|
|
2023-12-15 17:34:50 +03:00
|
|
|
import clsx from 'clsx';
|
2023-07-25 20:27:29 +03:00
|
|
|
|
2023-12-13 14:32:57 +03:00
|
|
|
import useEscapeKey from '@/hooks/useEscapeKey';
|
2024-10-29 12:06:43 +03:00
|
|
|
import { HelpTopic } from '@/models/miscellaneous';
|
|
|
|
import { PARAMETER } from '@/utils/constants';
|
2024-03-09 16:40:10 +03:00
|
|
|
import { prepareTooltip } from '@/utils/labels';
|
2023-12-13 14:32:57 +03:00
|
|
|
|
2024-04-03 21:05:53 +03:00
|
|
|
import { IconClose } from '../Icons';
|
2024-10-29 12:06:43 +03:00
|
|
|
import BadgeHelp from '../info/BadgeHelp';
|
2023-12-18 19:42:27 +03:00
|
|
|
import { CProps } from '../props';
|
2023-07-25 20:27:29 +03:00
|
|
|
import Button from './Button';
|
2023-12-04 14:19:54 +03:00
|
|
|
import MiniButton from './MiniButton';
|
2023-12-05 01:22:44 +03:00
|
|
|
import Overlay from './Overlay';
|
2023-07-22 12:24:14 +03:00
|
|
|
|
2023-12-28 14:04:44 +03:00
|
|
|
export interface ModalProps extends CProps.Styling {
|
2024-11-21 15:09:51 +03:00
|
|
|
/** Title of the modal window. */
|
2023-12-28 14:04:44 +03:00
|
|
|
header?: string;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Text of the submit button. */
|
2023-12-28 14:04:44 +03:00
|
|
|
submitText?: string;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Tooltip for the submit button when the form is invalid. */
|
2023-12-28 14:04:44 +03:00
|
|
|
submitInvalidTooltip?: string;
|
2023-12-18 19:42:27 +03:00
|
|
|
|
2024-11-21 15:09:51 +03:00
|
|
|
/** Indicates that form is readonly. */
|
2023-12-28 14:04:44 +03:00
|
|
|
readonly?: boolean;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Indicates that submit button is enabled. */
|
2023-12-28 14:04:44 +03:00
|
|
|
canSubmit?: boolean;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Indicates that the modal window should be scrollable. */
|
2024-06-05 14:43:52 +03:00
|
|
|
overflowVisible?: boolean;
|
2023-12-18 19:42:27 +03:00
|
|
|
|
2024-11-21 15:09:51 +03:00
|
|
|
/** Callback to be called when the modal window is closed. */
|
2023-12-28 14:04:44 +03:00
|
|
|
hideWindow: () => void;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Callback to be called before submit. */
|
2024-08-30 20:18:21 +03:00
|
|
|
beforeSubmit?: () => boolean;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Callback to be called after submit. */
|
2023-12-28 14:04:44 +03:00
|
|
|
onSubmit?: () => void;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Callback to be called after cancel. */
|
2023-12-28 14:04:44 +03:00
|
|
|
onCancel?: () => void;
|
2024-10-29 12:06:43 +03:00
|
|
|
|
2024-11-21 15:09:51 +03:00
|
|
|
/** Help topic to be displayed in the modal window. */
|
2024-10-29 12:06:43 +03:00
|
|
|
helpTopic?: HelpTopic;
|
2024-11-21 15:09:51 +03:00
|
|
|
|
|
|
|
/** Callback to determine if help should be displayed. */
|
2024-10-29 12:06:43 +03:00
|
|
|
hideHelpWhen?: () => boolean;
|
2023-07-22 12:24:14 +03:00
|
|
|
}
|
|
|
|
|
2024-11-21 15:09:51 +03:00
|
|
|
/**
|
|
|
|
* Displays a customizable modal window.
|
|
|
|
*/
|
2023-12-28 14:04:44 +03:00
|
|
|
function Modal({
|
2024-10-29 12:06:43 +03:00
|
|
|
children,
|
|
|
|
|
2023-12-28 14:04:44 +03:00
|
|
|
header,
|
2024-10-29 12:06:43 +03:00
|
|
|
submitText = 'Продолжить',
|
|
|
|
submitInvalidTooltip,
|
|
|
|
|
|
|
|
readonly,
|
|
|
|
canSubmit,
|
|
|
|
overflowVisible,
|
|
|
|
|
2023-12-28 14:04:44 +03:00
|
|
|
hideWindow,
|
2024-08-30 20:18:21 +03:00
|
|
|
beforeSubmit,
|
2023-12-28 14:04:44 +03:00
|
|
|
onSubmit,
|
|
|
|
onCancel,
|
|
|
|
className,
|
2024-10-29 12:06:43 +03:00
|
|
|
|
|
|
|
helpTopic,
|
|
|
|
hideHelpWhen,
|
2023-12-18 19:42:27 +03:00
|
|
|
...restProps
|
2024-09-19 17:49:25 +03:00
|
|
|
}: React.PropsWithChildren<ModalProps>) {
|
2023-07-25 22:29:33 +03:00
|
|
|
useEscapeKey(hideWindow);
|
2023-07-22 12:24:14 +03:00
|
|
|
|
|
|
|
const handleCancel = () => {
|
2023-07-25 22:29:33 +03:00
|
|
|
hideWindow();
|
2024-12-04 22:53:01 +03:00
|
|
|
onCancel?.();
|
2023-07-22 12:24:14 +03:00
|
|
|
};
|
|
|
|
|
2023-07-23 15:23:01 +03:00
|
|
|
const handleSubmit = () => {
|
2024-08-30 20:18:21 +03:00
|
|
|
if (beforeSubmit && !beforeSubmit()) {
|
|
|
|
return;
|
|
|
|
}
|
2024-12-04 22:53:01 +03:00
|
|
|
onSubmit?.();
|
2024-08-30 20:18:21 +03:00
|
|
|
hideWindow();
|
2023-07-23 15:23:01 +03:00
|
|
|
};
|
|
|
|
|
2023-12-04 14:19:54 +03:00
|
|
|
return (
|
2024-10-29 12:06:43 +03:00
|
|
|
<div className='fixed top-0 left-0 w-full h-full z-modal cursor-default'>
|
2024-12-17 10:53:01 +03:00
|
|
|
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'backdrop-blur-[3px] opacity-50')} />
|
2024-11-28 14:10:44 +03:00
|
|
|
<div
|
2024-12-17 10:53:01 +03:00
|
|
|
className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'bg-prim-0 opacity-25')}
|
2024-11-28 14:10:44 +03:00
|
|
|
onClick={hideWindow}
|
|
|
|
/>
|
2024-12-12 13:19:12 +03:00
|
|
|
<div
|
2024-05-10 15:28:33 +03:00
|
|
|
className={clsx(
|
2024-12-12 13:19:12 +03:00
|
|
|
'cc-animate-modal',
|
|
|
|
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
2024-12-17 10:53:01 +03:00
|
|
|
'border rounded-xl bg-prim-100'
|
2024-05-10 15:28:33 +03:00
|
|
|
)}
|
2023-12-07 01:21:27 +03:00
|
|
|
>
|
2024-03-27 22:54:24 +03:00
|
|
|
<Overlay position='right-2 top-2'>
|
2024-03-09 16:40:10 +03:00
|
|
|
<MiniButton
|
2024-03-27 22:54:24 +03:00
|
|
|
noPadding
|
2024-03-09 16:40:10 +03:00
|
|
|
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
2024-04-03 21:05:53 +03:00
|
|
|
icon={<IconClose size='1.25rem' />}
|
2024-03-09 16:40:10 +03:00
|
|
|
onClick={handleCancel}
|
|
|
|
/>
|
2023-12-28 14:04:44 +03:00
|
|
|
</Overlay>
|
2024-10-29 12:06:43 +03:00
|
|
|
{helpTopic && !hideHelpWhen?.() ? (
|
|
|
|
<Overlay position='left-2 top-2'>
|
|
|
|
<BadgeHelp topic={helpTopic} className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')} padding='p-0' />
|
|
|
|
</Overlay>
|
|
|
|
) : null}
|
2023-12-28 14:04:44 +03:00
|
|
|
|
|
|
|
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
|
|
|
|
|
|
|
<div
|
2024-09-06 13:50:00 +03:00
|
|
|
className={clsx(
|
2024-12-12 13:19:12 +03:00
|
|
|
'overscroll-contain max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)] outline-none',
|
2024-09-06 13:50:00 +03:00
|
|
|
{
|
|
|
|
'overflow-auto': !overflowVisible,
|
|
|
|
'overflow-visible': overflowVisible
|
|
|
|
},
|
|
|
|
className
|
|
|
|
)}
|
2024-12-12 13:19:12 +03:00
|
|
|
{...restProps}
|
2023-12-28 14:04:44 +03:00
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</div>
|
2023-12-04 14:19:54 +03:00
|
|
|
|
2024-09-10 17:40:58 +03:00
|
|
|
<div className='z-modalControls my-2 flex gap-12 justify-center text-sm'>
|
2023-12-28 14:04:44 +03:00
|
|
|
{!readonly ? (
|
|
|
|
<Button
|
|
|
|
autoFocus
|
|
|
|
text={submitText}
|
|
|
|
title={!canSubmit ? submitInvalidTooltip : ''}
|
2024-09-10 17:40:58 +03:00
|
|
|
className='min-w-[7rem]'
|
2023-12-28 14:04:44 +03:00
|
|
|
colors='clr-btn-primary'
|
|
|
|
disabled={!canSubmit}
|
|
|
|
onClick={handleSubmit}
|
|
|
|
/>
|
|
|
|
) : null}
|
2024-09-10 17:40:58 +03:00
|
|
|
<Button text={readonly ? 'Закрыть' : 'Отмена'} className='min-w-[7rem]' onClick={handleCancel} />
|
2023-12-28 14:04:44 +03:00
|
|
|
</div>
|
2024-12-12 13:19:12 +03:00
|
|
|
</div>
|
2024-05-10 15:28:33 +03:00
|
|
|
</div>
|
2023-12-28 14:04:44 +03:00
|
|
|
);
|
2023-07-22 12:24:14 +03:00
|
|
|
}
|
|
|
|
|
2023-12-28 14:04:44 +03:00
|
|
|
export default Modal;
|