ConceptPortal-public/rsconcept/frontend/src/components/Modal/ModalForm.tsx

147 lines
3.9 KiB
TypeScript
Raw Normal View History

'use client';
import clsx from 'clsx';
2023-07-25 20:27:29 +03:00
2025-02-26 00:16:41 +03:00
import { type HelpTopic } from '@/features/help';
import { BadgeHelp } from '@/features/help/components';
2025-02-12 21:36:25 +03:00
2025-02-19 23:30:35 +03:00
import { useEscapeKey } from '@/hooks/useEscapeKey';
import { useDialogsStore } from '@/stores/dialogs';
2024-10-29 12:06:43 +03:00
import { PARAMETER } from '@/utils/constants';
2025-02-11 20:56:24 +03:00
import { prepareTooltip } from '@/utils/utils';
2025-02-07 10:54:47 +03:00
import { Button, MiniButton, SubmitButton } from '../Control';
import { IconClose } from '../Icons';
import { type Styling } from '../props';
2025-02-12 21:36:25 +03:00
import { ModalBackdrop } from './ModalBackdrop';
2023-07-22 12:24:14 +03:00
export interface ModalProps extends Styling {
/** Title of the modal window. */
2023-12-28 14:04:44 +03:00
header?: string;
/** Indicates that the modal window should be scrollable. */
overflowVisible?: boolean;
/** Help topic to be displayed in the modal window. */
helpTopic?: HelpTopic;
/** Callback to determine if help should be displayed. */
hideHelpWhen?: () => boolean;
}
interface ModalFormProps extends ModalProps {
/** Text of the submit button. */
2023-12-28 14:04:44 +03:00
submitText?: string;
/** Tooltip for the submit button when the form is invalid. */
2023-12-28 14:04:44 +03:00
submitInvalidTooltip?: string;
/** Indicates that submit button is enabled. */
2023-12-28 14:04:44 +03:00
canSubmit?: boolean;
/** Callback to be called before submit. */
2024-08-30 20:18:21 +03:00
beforeSubmit?: () => boolean;
/** Callback to be called after submit. */
2025-02-15 16:43:10 +03:00
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
2025-02-15 15:34:29 +03:00
/** Callback to be called when modal is canceled. */
onCancel?: () => void;
2023-07-22 12:24:14 +03:00
}
/**
* Displays a customizable modal window with submit form.
*/
export function ModalForm({
2024-10-29 12:06:43 +03:00
children,
className,
2023-12-28 14:04:44 +03:00
header,
2024-10-29 12:06:43 +03:00
overflowVisible,
canSubmit = true,
submitText = 'Продолжить',
submitInvalidTooltip,
2024-08-30 20:18:21 +03:00
beforeSubmit,
2023-12-28 14:04:44 +03:00
onSubmit,
2025-02-15 15:34:29 +03:00
onCancel,
2024-10-29 12:06:43 +03:00
helpTopic,
hideHelpWhen,
...restProps
}: React.PropsWithChildren<ModalFormProps>) {
const hideDialog = useDialogsStore(state => state.hideDialog);
2025-02-15 15:34:29 +03:00
function handleCancel() {
onCancel?.();
hideDialog();
}
useEscapeKey(handleCancel);
2023-07-22 12:24:14 +03:00
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
2024-08-30 20:18:21 +03:00
if (beforeSubmit && !beforeSubmit()) {
return;
}
2025-02-15 16:43:10 +03:00
onSubmit(event);
hideDialog();
}
2023-12-04 14:19:54 +03:00
return (
2025-03-07 20:38:40 +03:00
<div className='fixed top-0 left-0 w-full h-full z-modal isolate cursor-default'>
2025-02-15 15:34:29 +03:00
<ModalBackdrop onHide={handleCancel} />
<form
2024-05-10 15:28:33 +03:00
className={clsx(
'cc-animate-modal',
2025-03-07 20:38:40 +03:00
'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
)}
onSubmit={handleSubmit}
2023-12-07 01:21:27 +03:00
>
2024-10-29 12:06:43 +03:00
{helpTopic && !hideHelpWhen?.() ? (
2024-12-19 18:49:08 +03:00
<div className='float-left mt-2 ml-2'>
2024-10-29 12:06:43 +03:00
<BadgeHelp topic={helpTopic} className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')} padding='p-0' />
2024-12-19 18:49:08 +03:00
</div>
2024-10-29 12:06:43 +03:00
) : null}
2023-12-28 14:04:44 +03:00
2025-03-07 20:38:40 +03:00
<MiniButton
noPadding
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
icon={<IconClose size='1.25rem' />}
className='float-right mt-2 mr-2'
onClick={handleCancel}
/>
2024-12-19 18:49:08 +03:00
2023-12-28 14:04:44 +03:00
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
<div
className={clsx(
'@container/modal',
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
'overscroll-contain outline-hidden',
{
'overflow-auto': !overflowVisible,
'overflow-visible': overflowVisible
},
className
)}
{...restProps}
2023-12-28 14:04:44 +03:00
>
{children}
</div>
2023-12-04 14:19:54 +03:00
2025-03-07 20:38:40 +03:00
<div className='z-pop my-2 flex gap-12 justify-center text-sm'>
<SubmitButton
autoFocus
text={submitText}
title={!canSubmit ? submitInvalidTooltip : ''}
className='min-w-[7rem]'
disabled={!canSubmit}
/>
2025-02-15 15:34:29 +03:00
<Button text='Отмена' className='min-w-[7rem]' onClick={handleCancel} />
2023-12-28 14:04:44 +03:00
</div>
</form>
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
}