Portal/rsconcept/frontend/src/components/modal/modal-view.tsx

105 lines
3.0 KiB
TypeScript
Raw Normal View History

2025-02-06 20:27:56 +03:00
'use client';
import clsx from 'clsx';
2025-02-26 00:16:22 +03:00
import { BadgeHelp } from '@/features/help/components';
2025-02-12 21:36:03 +03:00
2025-03-12 11:54:32 +03:00
import { useEscapeKey } from '@/hooks/use-escape-key';
2025-02-06 20:27:56 +03:00
import { useDialogsStore } from '@/stores/dialogs';
2025-02-11 20:56:11 +03:00
import { prepareTooltip } from '@/utils/utils';
2025-02-06 20:27:56 +03:00
2025-03-12 12:04:23 +03:00
import { Button, MiniButton } from '../control';
import { IconClose } from '../icons';
2025-02-12 21:36:03 +03:00
2025-03-12 11:54:32 +03:00
import { ModalBackdrop } from './modal-backdrop';
import { type ModalProps } from './modal-form';
2025-02-06 20:27:56 +03:00
interface ModalViewProps extends ModalProps {
/** Float all UI elements on top of contents. */
fullScreen?: boolean;
}
2025-02-06 20:27:56 +03:00
/**
* Displays a customizable modal window with submit form.
*/
export function ModalView({
children,
className,
header,
overflowVisible,
helpTopic,
hideHelpWhen,
fullScreen,
2025-02-06 20:27:56 +03:00
...restProps
}: React.PropsWithChildren<ModalViewProps>) {
const hideDialog = useDialogsStore(state => state.hideDialog);
useEscapeKey(hideDialog);
return (
2025-03-10 16:01:40 +03:00
<div className='cc-modal-wrapper'>
2025-02-06 20:27:56 +03:00
<ModalBackdrop onHide={hideDialog} />
2025-03-11 12:56:32 +03:00
<div className='cc-animate-modal relative grid border rounded-xl bg-prim-100' role='dialog'>
2025-02-06 20:27:56 +03:00
{helpTopic && !hideHelpWhen?.() ? (
2025-03-09 21:57:21 +03:00
<BadgeHelp
topic={helpTopic}
2025-03-11 12:56:32 +03:00
className='absolute z-pop top-2 left-2'
2025-03-09 21:57:21 +03:00
padding='p-0'
contentClass='sm:max-w-160'
/>
2025-02-06 20:27:56 +03:00
) : null}
2025-03-07 16:21:18 +03:00
<MiniButton
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
2025-03-20 11:33:19 +03:00
aria-label='Закрыть'
noPadding
2025-03-07 16:21:18 +03:00
icon={<IconClose size='1.25rem' />}
2025-03-11 12:56:32 +03:00
className='absolute z-pop top-2 right-2'
2025-03-07 16:21:18 +03:00
onClick={hideDialog}
/>
2025-02-06 20:27:56 +03:00
{header ? (
<h1
className={clsx(
'px-12 py-2 select-none',
2025-03-13 13:30:31 +03:00
fullScreen && 'z-pop absolute top-0 right-1/2 translate-x-1/2 backdrop-blur-xs bg-prim-100/90 rounded-2xl'
)}
>
{header}
</h1>
) : null}
2025-02-06 20:27:56 +03:00
<div
className={clsx(
'@container/modal',
'max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
'overscroll-contain outline-hidden',
2025-03-13 01:14:47 +03:00
overflowVisible ? 'overflow-visible' : 'overflow-auto',
fullScreen ? 'max-h-[calc(100svh-2rem)]' : 'max-h-[calc(100svh-8rem)]',
2025-02-06 20:27:56 +03:00
className
)}
{...restProps}
>
{children}
</div>
{!fullScreen ? (
<Button
text='Закрыть'
aria-label='Закрыть'
className={clsx(
'my-2 mx-auto text-sm min-w-28',
2025-03-13 13:30:31 +03:00
fullScreen && 'z-pop absolute bottom-0 right-1/2 translate-x-1/2'
)}
onClick={hideDialog}
/>
) : (
2025-03-13 13:30:31 +03:00
<div className='z-pop absolute bottom-0 right-1/2 translate-x-1/2 p-3 rounded-xl bg-prim-100/90 backdrop-blur-xs'>
{' '}
<Button text='Закрыть' aria-label='Закрыть' className='text-sm min-w-28' onClick={hideDialog} />
</div>
)}
2025-02-06 20:27:56 +03:00
</div>
</div>
);
}