ConceptPortal-public/rsconcept/frontend/src/dialogs/DlgCreateCst/FormCreateCst.tsx

149 lines
5.6 KiB
TypeScript
Raw Normal View History

2024-04-01 15:11:17 +03:00
'use client';
2024-06-09 20:41:33 +03:00
import clsx from 'clsx';
2024-04-01 15:11:17 +03:00
import { AnimatePresence } from 'framer-motion';
2024-08-29 12:42:26 +03:00
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
2024-04-01 15:11:17 +03:00
2024-05-16 22:39:28 +03:00
import BadgeHelp from '@/components/info/BadgeHelp';
2024-04-01 15:11:17 +03:00
import RSInput from '@/components/RSInput';
import SelectSingle from '@/components/ui/SelectSingle';
import TextArea from '@/components/ui/TextArea';
import TextInput from '@/components/ui/TextInput';
import AnimateFade from '@/components/wrap/AnimateFade';
2024-04-01 19:07:20 +03:00
import { HelpTopic } from '@/models/miscellaneous';
2024-04-01 15:11:17 +03:00
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
import { generateAlias, isBaseSet, isBasicConcept, isFunctional, validateNewAlias } from '@/models/rsformAPI';
2024-06-09 20:41:33 +03:00
import { PARAMETER } from '@/utils/constants';
2024-04-01 15:11:17 +03:00
import { labelCstType } from '@/utils/labels';
import { SelectorCstType } from '@/utils/selectors';
interface FormCreateCstProps {
schema: IRSForm;
state: ICstCreateData;
partialUpdate: React.Dispatch<Partial<ICstCreateData>>;
2024-05-23 13:06:23 +03:00
setValidated?: React.Dispatch<React.SetStateAction<boolean>>;
2024-04-01 15:11:17 +03:00
}
function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreateCstProps) {
const [forceComment, setForceComment] = useState(false);
const isBasic = useMemo(() => isBasicConcept(state.cst_type), [state]);
const isElementary = useMemo(() => isBaseSet(state.cst_type), [state]);
const showConvention = useMemo(() => !!state.convention || forceComment || isBasic, [state, forceComment, isBasic]);
useLayoutEffect(() => {
setForceComment(false);
}, [state.cst_type, partialUpdate, schema]);
useLayoutEffect(() => {
2024-05-23 13:06:23 +03:00
if (setValidated) {
setValidated(validateNewAlias(state.alias, state.cst_type, schema));
}
2024-04-01 15:11:17 +03:00
}, [state.alias, state.cst_type, schema, setValidated]);
2024-08-29 12:42:26 +03:00
const handleTypeChange = useCallback(
(target: CstType) => partialUpdate({ cst_type: target, alias: generateAlias(target, schema) }),
[partialUpdate, schema, generateAlias]
);
2024-04-01 15:11:17 +03:00
return (
<AnimatePresence>
2024-08-29 12:42:26 +03:00
<div key='dlg_cst_alias_picker' className='flex items-center self-center gap-3'>
2024-04-01 15:11:17 +03:00
<SelectSingle
id='dlg_cst_type'
placeholder='Выберите тип'
className='w-[15rem]'
options={SelectorCstType}
value={{ value: state.cst_type, label: labelCstType(state.cst_type) }}
2024-08-29 12:42:26 +03:00
onChange={data => handleTypeChange(data?.value ?? CstType.BASE)}
2024-06-09 20:41:33 +03:00
/>
2024-04-01 15:11:17 +03:00
<TextInput
id='dlg_cst_alias'
dense
label='Имя'
2024-08-30 11:03:45 +03:00
className='w-[7rem]'
2024-04-01 15:11:17 +03:00
value={state.alias}
onChange={event => partialUpdate({ alias: event.target.value })}
/>
2024-08-29 12:42:26 +03:00
<BadgeHelp
topic={HelpTopic.CC_CONSTITUENTA}
offset={16}
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
/>
2024-04-01 15:11:17 +03:00
</div>
<TextArea
key='dlg_cst_term'
2024-04-01 15:11:17 +03:00
id='dlg_cst_term'
2024-08-28 22:38:50 +03:00
fitContent
2024-04-01 15:11:17 +03:00
spellCheck
label='Термин'
placeholder='Обозначение для текстовых определений'
2024-08-28 22:38:50 +03:00
className='max-h-[3.6rem]'
2024-04-01 15:11:17 +03:00
value={state.term_raw}
onChange={event => partialUpdate({ term_raw: event.target.value })}
/>
<AnimateFade key='dlg_cst_expression' hideContent={!state.definition_formal && isElementary}>
2024-04-01 15:11:17 +03:00
<RSInput
id='dlg_cst_expression'
2024-08-29 12:42:26 +03:00
noTooltip
2024-04-01 15:11:17 +03:00
label={
state.cst_type === CstType.STRUCTURED
? 'Область определения'
: isFunctional(state.cst_type)
? 'Определение функции'
: 'Формальное определение'
}
placeholder={
state.cst_type !== CstType.STRUCTURED
? 'Родоструктурное выражение'
: 'Определение множества, которому принадлежат элементы родовой структуры'
}
value={state.definition_formal}
onChange={value => partialUpdate({ definition_formal: value })}
2024-06-18 19:55:23 +03:00
schema={schema}
2024-04-01 15:11:17 +03:00
/>
</AnimateFade>
<AnimateFade key='dlg_cst_definition' hideContent={!state.definition_raw && isElementary}>
2024-04-01 15:11:17 +03:00
<TextArea
id='dlg_cst_definition'
spellCheck
2024-08-28 22:38:50 +03:00
fitContent
2024-04-01 15:11:17 +03:00
label='Текстовое определение'
placeholder='Текстовая интерпретация формального выражения'
2024-08-28 22:38:50 +03:00
className='max-h-[3.6rem]'
2024-04-01 15:11:17 +03:00
value={state.definition_raw}
onChange={event => partialUpdate({ definition_raw: event.target.value })}
/>
</AnimateFade>
{!showConvention ? (
<button
key='dlg_cst_show_comment'
id='dlg_cst_show_comment'
2024-05-11 20:53:36 +03:00
tabIndex={-1}
2024-04-01 15:11:17 +03:00
type='button'
className='self-start cc-label clr-text-url hover:underline'
onClick={() => setForceComment(true)}
>
Добавить комментарий
</button>
) : null}
<AnimateFade hideContent={!showConvention}>
<TextArea
key='dlg_cst_convention'
2024-04-01 15:11:17 +03:00
id='dlg_cst_convention'
spellCheck
2024-08-28 22:38:50 +03:00
fitContent
2024-04-01 15:11:17 +03:00
label={isBasic ? 'Конвенция' : 'Комментарий'}
placeholder={isBasic ? 'Договоренность об интерпретации' : 'Пояснение разработчика'}
2024-08-28 22:38:50 +03:00
className='max-h-[5.4rem]'
2024-04-01 15:11:17 +03:00
value={state.convention}
onChange={event => partialUpdate({ convention: event.target.value })}
/>
</AnimateFade>
</AnimatePresence>
);
}
export default FormCreateCst;