import { useLayoutEffect, useMemo, useState } from 'react'; import { toast } from 'react-toastify'; import ConceptTooltip from '../../components/Common/ConceptTooltip'; import Divider from '../../components/Common/Divider'; import MiniButton from '../../components/Common/MiniButton'; import SubmitButton from '../../components/Common/SubmitButton'; import TextArea from '../../components/Common/TextArea'; import CstStatusInfo from '../../components/Help/InfoCstStatus'; import { DumpBinIcon, HelpIcon, PenIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons'; import { useRSForm } from '../../context/RSFormContext'; import { CstType, EditMode, ICstCreateData, ICstRenameData, ICstUpdateData, SyntaxTree } from '../../utils/models'; import { getCstTypificationLabel } from '../../utils/staticUI'; import EditorRSExpression from './EditorRSExpression'; import ViewSideConstituents from './elements/ViewSideConstituents'; // Max height of content for left enditor pane const UNFOLDED_HEIGHT = '59.1rem'; interface EditorConstituentaProps { activeID?: number onOpenEdit: (cstID: number) => void onShowAST: (expression: string, ast: SyntaxTree) => void onCreateCst: (initial: ICstCreateData, skipDialog?: boolean) => void onRenameCst: (initial: ICstRenameData) => void onDeleteCst: (selected: number[], callback?: (items: number[]) => void) => void } function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onOpenEdit, onDeleteCst }: EditorConstituentaProps) { const { schema, processing, isEditable, cstUpdate } = useRSForm(); const activeCst = useMemo( () => { return schema?.items?.find((cst) => cst.id === activeID); }, [schema?.items, activeID]); const [isModified, setIsModified] = useState(false); const [editMode, setEditMode] = useState(EditMode.TEXT); const [alias, setAlias] = useState(''); const [term, setTerm] = useState(''); const [textDefinition, setTextDefinition] = useState(''); const [expression, setExpression] = useState(''); const [convention, setConvention] = useState(''); const [typification, setTypification] = useState('N/A'); const isEnabled = useMemo(() => activeCst && isEditable, [activeCst, isEditable]); useLayoutEffect(() => { if (!activeCst) { setIsModified(false); return; } setIsModified( activeCst.term.raw !== term || activeCst.definition.text.raw !== textDefinition || activeCst.convention !== convention || activeCst.definition.formal !== expression ); }, [activeCst, activeCst?.term, activeCst?.definition.formal, activeCst?.definition.text.raw, activeCst?.convention, term, textDefinition, expression, convention]); useLayoutEffect(() => { if (activeCst) { setAlias(activeCst.alias); setConvention(activeCst.convention ?? ''); setTerm(activeCst.term?.raw ?? ''); setTextDefinition(activeCst.definition?.text?.raw ?? ''); setExpression(activeCst.definition?.formal ?? ''); setTypification(activeCst ? getCstTypificationLabel(activeCst) : 'N/A'); } else if (schema && schema?.items.length > 0) { onOpenEdit(schema.items[0].id); } }, [activeCst, onOpenEdit, schema]); function handleSubmit(event: React.FormEvent) { event.preventDefault(); if (!activeID || processing) { return; } const data: ICstUpdateData = { id: activeID, alias: alias, convention: convention, definition_formal: expression, definition_raw: textDefinition, term_raw: term }; cstUpdate(data, () => { toast.success('Изменения сохранены'); }); } function handleDelete() { if (!schema || !activeID) { return; } onDeleteCst([activeID]); } function handleCreateCst() { if (!activeID || !schema) { return; } const data: ICstCreateData = { insert_after: activeID, cst_type: activeCst?.cstType ?? CstType.BASE, alias: '', term_raw: '', definition_formal: '', definition_raw: '', convention: '', }; onCreateCst(data); } function handleRename() { if (!activeID || !activeCst) { return; } const data: ICstRenameData = { id: activeID, alias: activeCst?.alias, cst_type: activeCst.cstType }; onRenameCst(data); } return (
} >
} /> } />

Подсказки

Изменения сохраняются ПОСЛЕ нажатия на кнопку снизу или слева вверху

Клик на формальное выражение - обратите внимание на кнопки снизу.
Для каждой есть горячая клавиша в подсказке

Список конституент справа - обратите внимание на настройки фильтрации

- слева от ввода текста настраивается набор атрибутов конституенты

- справа от ввода текста настраивается список конституент, которые фильтруются

- текущая конституента выделена цветом строки

- двойной клик / Alt + клик - выбор редактируемой конституенты

- при наведении на ID конституенты отображаются ее атрибуты

- столбец "Описание" содержит один из непустых текстовых атрибутов

Конституента {alias}
} />