Implement reference dialog

This commit is contained in:
IRBorisov 2023-09-29 15:33:32 +03:00
parent 4eef460be1
commit edff9b640a
15 changed files with 504 additions and 50 deletions

View File

@ -8,24 +8,27 @@ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'>
dimensions?: string
colorClass?: string
singleRow?: boolean
noBorder?: boolean
}
function TextInput({
id, required, label, singleRow, tooltip,
id, required, label, singleRow, tooltip, noBorder,
dimensions = 'w-full',
colorClass = 'clr-input',
...props
}: TextInputProps) {
const borderClass = noBorder ? '': 'border';
return (
<div className={`flex ${singleRow ? 'items-center gap-4 ' + dimensions : 'flex-col items-start gap-2'}`}>
{label && <Label
{label &&
<Label
text={label}
required={!props.disabled && required}
htmlFor={id}
/>}
<input id={id}
title={tooltip}
className={`px-3 py-2 leading-tight border shadow truncate hover:text-clip clr-outline ${colorClass} ${singleRow ? '' : dimensions}`}
className={`px-3 py-2 leading-tight ${borderClass} shadow truncate hover:text-clip clr-outline ${colorClass} ${singleRow ? 'w-full' : dimensions}`}
required={required}
{...props}
/>

View File

@ -26,7 +26,7 @@ const editorSetup: BasicSetupOptions = {
lineNumbers: false,
highlightActiveLineGutter: false,
foldGutter: false,
dropCursor: false,
dropCursor: true,
allowMultipleSelections: false,
indentOnInput: false,
bracketMatching: false,

View File

@ -0,0 +1,304 @@
import { createColumnHelper } from '@tanstack/react-table';
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { useConceptTheme } from '../../context/ThemeContext';
import { getCompatibleGrams, Grammeme, parseEntityReference,parseGrammemes,parseSyntacticReference,ReferenceType } from '../../models/language';
import { CstMatchMode } from '../../models/miscelanious';
import { IConstituenta, matchConstituenta } from '../../models/rsform';
import ConstituentaTooltip from '../../pages/RSFormPage/elements/ConstituentaTooltip';
import { colorfgCstStatus } from '../../utils/color';
import { prefixes } from '../../utils/constants';
import { labelReferenceType } from '../../utils/labels';
import { compareGrammemeOptions, IGrammemeOption, PremadeWordForms, SelectorGrammems, SelectorReferenceType } from '../../utils/selectors';
import Label from '../Common/Label';
import Modal from '../Common/Modal';
import SelectMulti from '../Common/SelectMulti';
import SelectSingle from '../Common/SelectSingle';
import TextInput from '../Common/TextInput';
import DataTable, { IConditionalStyle } from '../DataTable';
import TermformButton from './TermformButton';
interface DlgEditReferenceProps {
hideWindow: () => void
items: IConstituenta[]
initialType: ReferenceType
initialRef?: string
initialText?: string
onSave: (newRef: string) => void
}
const constituentaHelper = createColumnHelper<IConstituenta>();
function DlgEditReference({ hideWindow, items, initialRef, initialText, initialType, onSave }: DlgEditReferenceProps) {
const { colors } = useConceptTheme();
const [type, setType] = useState<ReferenceType>(ReferenceType.ENTITY);
const [nominal, setNominal] = useState('');
const [offset, setOffset] = useState(1);
const [alias, setAlias] = useState('');
const [term, setTerm] = useState('');
const [filter, setFilter] = useState('');
const [filteredData, setFilteredData] = useState<IConstituenta[]>([]);
const [selectedGrams, setSelectedGrams] = useState<IGrammemeOption[]>([]);
const [gramOptions, setGramOptions] = useState<IGrammemeOption[]>([]);
const isValid = useMemo(
() => {
if (type === ReferenceType.ENTITY) {
return alias !== '' && selectedGrams.length > 0;
} else if (type === ReferenceType.SYNTACTIC) {
return nominal !== '' && offset !== 0;
} else {
return false;
}
}, [type, alias, selectedGrams, nominal, offset]);
function produceReference(): string {
if (type === ReferenceType.ENTITY) {
return `@{${alias}|${selectedGrams.map(gram => gram.value).join(',')}}`;
} else if (type === ReferenceType.SYNTACTIC) {
return `@{${offset}|${nominal}}`;
} else {
return '';
}
}
// Initialization
useLayoutEffect(
() => {
setType(initialType);
if (initialRef) {
if (initialType === ReferenceType.ENTITY) {
const ref = parseEntityReference(initialRef);
setAlias(ref.entity);
const grams = parseGrammemes(ref.form);
setSelectedGrams(SelectorGrammems.filter(data => grams.includes(data.value)));
} else if (initialType === ReferenceType.SYNTACTIC) {
const ref = parseSyntacticReference(initialRef);
setOffset(ref.offset);
setNominal(ref.nominal);
}
} else if (initialText) {
setNominal(initialText ?? '');
setFilter(initialText);
}
}, [initialRef, initialText, initialType, items]);
// Filter constituents
useEffect(
() => {
if (filter === '') {
setFilteredData(items.filter(
(cst) => cst.term_resolved !== '')
);
} else {
setFilteredData(items.filter(
(cst) => matchConstituenta(filter, cst, CstMatchMode.TERM))
);
}
}, [filter, items]);
// Filter grammemes when input changes
useEffect(
() => {
const compatible = getCompatibleGrams(
selectedGrams
.filter(data => Object.values(Grammeme).includes(data.value as Grammeme))
.map(data => data.value as Grammeme)
);
setGramOptions(SelectorGrammems.filter(({value}) => compatible.includes(value as Grammeme)));
}, [selectedGrams]);
// Update term when alias changes
useEffect(
() => {
const cst = items.find(item => item.alias === alias)
setTerm(cst?.term_resolved ?? '')
}, [alias, term, items]);
const handleSubmit = () => onSave(produceReference());
function handleSelectConstituenta(cst: IConstituenta) {
setAlias(cst.alias);
}
const handleSelectGrams = useCallback(
(grams: Grammeme[]) => {
setSelectedGrams(SelectorGrammems.filter(({value}) => grams.includes(value as Grammeme)));
}, []);
const FormButtons = useMemo(() => {
return (
<div className='flex flex-col items-center w-full text-sm'>
<div className='flex flex-start'>
{PremadeWordForms.slice(0, 6).map(
(data, index) =>
<TermformButton id={`${prefixes.wordform_list}${index}`}
text={data.text} example={data.example} grams={data.grams}
isSelected={data.grams.every(gram => selectedGrams.find(item => item.value as Grammeme === gram))}
onSelectGrams={handleSelectGrams}
/>
)}
</div>
<div className='flex flex-start'>
{PremadeWordForms.slice(6, 12).map(
(data, index) =>
<TermformButton id={`${prefixes.wordform_list}${index}`}
text={data.text} example={data.example} grams={data.grams}
isSelected={data.grams.every(gram => selectedGrams.find(item => item.value as Grammeme === gram))}
onSelectGrams={handleSelectGrams}
/>
)}
</div>
</div>);
}, [handleSelectGrams, selectedGrams]);
const columnsConstituenta = useMemo(
() => [
constituentaHelper.accessor('alias', {
id: 'alias',
header: 'Имя',
size: 65,
minSize: 65,
cell: props => {
const cst = props.row.original;
return (<>
<div
id={`${prefixes.cst_list}${cst.alias}`}
className='min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap'
style={{
borderWidth: '1px',
borderColor: colorfgCstStatus(cst.status, colors),
color: colorfgCstStatus(cst.status, colors),
fontWeight: 600
}}
>
{cst.alias}
</div>
<ConstituentaTooltip data={cst} anchor={`#${prefixes.cst_list}${cst.alias}`} />
</>);
}
}),
constituentaHelper.accessor('term_resolved', {
id: 'term',
header: 'Термин',
size: 600,
minSize: 350,
maxSize: 600
})
], [colors]);
const conditionalRowStyles = useMemo(
(): IConditionalStyle<IConstituenta>[] => [
{
when: (cst: IConstituenta) => cst.alias === alias,
style: {
backgroundColor: colors.bgSelected
},
}
], [alias, colors]);
return (
<Modal
title='Редактирование ссылки'
hideWindow={hideWindow}
submitText='Сохранить ссылку'
canSubmit={isValid}
onSubmit={handleSubmit}
>
<div className='min-w-[40rem] flex flex-col gap-4 mb-4 mt-2'>
<SelectSingle
className='z-modal-top min-w-[20rem] w-fit self-center'
options={SelectorReferenceType}
isSearchable={false}
placeholder='Тип ссылки'
value={{ value: type, label: labelReferenceType(type) }}
onChange={data => setType(data?.value ?? ReferenceType.ENTITY)}
/>
{type === ReferenceType.SYNTACTIC &&
<div className='flex gap-4 flex-start'>
<TextInput id='offset' type='number'
label='Смещение'
dimensions='max-w-[10rem]'
singleRow
value={offset}
onChange={event => setOffset(event.target.valueAsNumber)}
/>
<TextInput id='nominal' type='text'
dimensions='w-full'
label='Начальная форма'
placeholder='зависимое слово в начальной форме'
spellCheck
singleRow
value={nominal}
onChange={event => setNominal(event.target.value)}
/>
</div>}
{type === ReferenceType.ENTITY &&
<div className='flex flex-col gap-2'>
<TextInput
dimensions='w-full'
placeholder='текст фильтра'
value={filter}
onChange={event => setFilter(event.target.value)}
/>
<div className='border min-h-[15.5rem] max-h-[15.5rem] text-sm overflow-y-auto'>
<DataTable
data={filteredData}
columns={columnsConstituenta}
conditionalRowStyles={conditionalRowStyles}
dense
noDataComponent={
<span className='flex flex-col justify-center p-2 text-center min-h-[5rem]'>
<p>Список конституент пуст</p>
<p>Измените параметры фильтра</p>
</span>
}
onRowClicked={handleSelectConstituenta}
/>
</div>
<div className='flex gap-4 flex-start'>
<TextInput
label='Отсылаемый идентификатор'
dimensions='max-w-[18rem] min-w-[18rem] whitespace-nowrap'
singleRow
value={alias}
onChange={event => setAlias(event.target.value)}
/>
<TextInput
label='Термин'
singleRow
disabled
noBorder
value={term}
tooltip={term}
dimensions='w-full'
/>
</div>
{FormButtons}
<div className='flex items-center gap-10 flex-start'>
<Label text='Отсылаемая словоформа'/>
<SelectMulti
className='flex-grow h-full z-modal-top'
options={gramOptions}
placeholder='Выберите граммемы'
value={selectedGrams}
onChange={newValue => setSelectedGrams([...newValue].sort(compareGrammemeOptions))}
/>
</div>
</div>}
</div>
</Modal>);
}
export default DlgEditReference;

View File

@ -0,0 +1,27 @@
import { Grammeme } from '../../models/language';
interface TermformButtonProps {
id?: string
text: string
example: string
grams: Grammeme[]
isSelected?: boolean
onSelectGrams: (grams: Grammeme[]) => void
}
function TermformButton({ text, example, grams, onSelectGrams, isSelected, ...props }: TermformButtonProps) {
return (
<button
type='button'
onClick={() => onSelectGrams(grams)}
tabIndex={-1}
className={`min-w-[6rem] p-1 border rounded-none cursor-pointer clr-btn-clear clr-hover ${isSelected ? 'clr-selected': ''}`}
{...props}
>
<p className='font-semibold'>{text}</p>
<p>{example}</p>
</button>
);
}
export default TermformButton;

View File

@ -9,11 +9,15 @@ import { RefObject, useCallback, useMemo, useRef, useState } from 'react';
import { useRSForm } from '../../context/RSFormContext';
import { useConceptTheme } from '../../context/ThemeContext';
import useResolveText from '../../hooks/useResolveText';
import { ReferenceType } from '../../models/language';
import { IConstituenta } from '../../models/rsform';
import { CodeMirrorWrapper } from '../../utils/codemirror';
import Label from '../Common/Label';
import Modal from '../Common/Modal';
import PrettyJson from '../Common/PrettyJSON';
import DlgEditReference from './DlgEditReference';
import { NaturalLanguage, ReferenceTokens } from './parse';
import { RefEntity } from './parse/parser.terms';
import { refsHoverTooltip } from './tooltip';
const editorSetup: BasicSetupOptions = {
@ -51,6 +55,7 @@ extends Pick<ReactCodeMirrorProps,
label?: string
innerref?: RefObject<ReactCodeMirrorRef> | undefined
onChange?: (newValue: string) => void
items?: IConstituenta[]
initialValue?: string
value?: string
@ -58,7 +63,7 @@ extends Pick<ReactCodeMirrorProps,
}
function RefsInput({
id, label, innerref, onChange, editable,
id, label, innerref, onChange, editable, items,
initialValue, value, resolved,
onFocus, onBlur,
...props
@ -71,6 +76,11 @@ function RefsInput({
const [showResolve, setShowResolve] = useState(false);
const [isFocused, setIsFocused] = useState(false);
const [showEditor, setShowEditor] = useState(false);
const [currentType, setCurrentType] = useState<ReferenceType>(ReferenceType.ENTITY);
const [refText, setRefText] = useState('');
const [hintText, setHintText] = useState('');
const internalRef = useRef<ReactCodeMirrorRef>(null);
const thisRef = useMemo(
() => {
@ -133,11 +143,41 @@ function RefsInput({
if (event.ctrlKey && event.code === 'Space') {
const wrap = new CodeMirrorWrapper(thisRef.current as Required<ReactCodeMirrorRef>);
wrap.fixSelection(ReferenceTokens);
const nodes = wrap.getEnvelopingNodes(ReferenceTokens);
if (nodes.length !== 1) {
setCurrentType(ReferenceType.ENTITY);
setRefText('');
setHintText(wrap.getSelectionText());
} else {
setCurrentType(nodes[0].type.id === RefEntity ? ReferenceType.ENTITY : ReferenceType.SYNTACTIC);
setRefText(wrap.getSelectionText());
}
setShowEditor(true);
}
}, [thisRef, resolveText, value]);
const handleInputReference = useCallback(
(referenceText: string) => {
if (!thisRef.current?.view) {
return;
}
thisRef.current.view.focus();
const wrap = new CodeMirrorWrapper(thisRef.current as Required<ReactCodeMirrorRef>);
wrap.replaceWith(referenceText);
}, [thisRef]);
return (
<>
{ showEditor &&
<DlgEditReference
hideWindow={() => setShowEditor(false)}
items={items ?? []}
initialType={currentType}
initialRef={refText}
initialText={hintText}
onSave={handleInputReference}
/>
}
{ showResolve &&
<Modal
readonly
@ -161,7 +201,7 @@ function RefsInput({
theme={customTheme}
extensions={editorExtensions}
value={isFocused ? value : (value !== initialValue ? value : resolved)}
value={isFocused ? value : (value !== initialValue || showEditor ? value : resolved)}
indentWithTab={false}
onChange={handleChange}

View File

@ -283,6 +283,39 @@ export function parseGrammemes(termForm: string): GramData[] {
return result.sort(compareGrammemes);
}
/**
* Creates a list of compatible {@link Grammeme}s.
*/
export function getCompatibleGrams(input: Grammeme[]): Grammeme[] {
let result: Grammeme[] = [];
input.forEach(
(gram) => {
if (!result.includes(gram)) {
if (NounGrams.includes(gram)) {
result.push(...NounGrams);
}
if (VerbGrams.includes(gram)) {
result.push(...VerbGrams);
}
}
});
input.forEach(
(gram) => GrammemeGroups.forEach(
(group) => {
if (group.includes(gram)) {
result = result.filter(item => !group.includes(item));
}
}));
if (result.length === 0) {
return [... new Set<Grammeme>([...VerbGrams, ...NounGrams])];
} else {
return result;
}
}
// ====== Reference resolution =====
/**
* Represents text request.
@ -324,11 +357,17 @@ export interface ITextPosition {
}
/**
* Represents single resolved reference data.
* Represents abstract reference data.
*/
export interface IResolvedReference {
export interface IReference {
type: ReferenceType
data: IEntityReference | ISyntacticReference
}
/**
* Represents single resolved reference data.
*/
export interface IResolvedReference extends IReference {
pos_input: ITextPosition
pos_output: ITextPosition
}

View File

@ -5,8 +5,8 @@ import SelectSingle from '../../components/Common/SelectSingle';
import TextArea from '../../components/Common/TextArea';
import RSInput from '../../components/RSInput';
import { CstType,ICstCreateData } from '../../models/rsform';
import { SelectorCstType } from '../../utils/selectors';
import { labelCstType } from '../../utils/labels';
import { SelectorCstType } from '../../utils/selectors';
interface DlgCreateCstProps
extends Pick<ModalProps, 'hideWindow'> {

View File

@ -10,15 +10,15 @@ import { ArrowLeftIcon, ArrowRightIcon, CheckIcon, ChevronDoubleDownIcon, CrossI
import { useConceptTheme } from '../../context/ThemeContext';
import useConceptText from '../../hooks/useConceptText';
import {
GramData, Grammeme, GrammemeGroups, ITextRequest, IWordForm,
IWordFormPlain, matchWordForm, NounGrams, parseGrammemes, VerbGrams
getCompatibleGrams, Grammeme, ITextRequest, IWordForm,
IWordFormPlain, matchWordForm, parseGrammemes
} from '../../models/language';
import { IConstituenta, TermForm } from '../../models/rsform';
import { colorfgGrammeme } from '../../utils/color';
import { labelGrammeme } from '../../utils/labels';
import { compareGrammemeOptions,IGrammemeOption, SelectorGrammemesList, SelectorGrammems } from '../../utils/selectors';
interface DlgEditTermProps {
interface DlgEditWordFormsProps {
hideWindow: () => void
target: IConstituenta
onSave: (data: TermForm[]) => void
@ -26,7 +26,7 @@ interface DlgEditTermProps {
const columnHelper = createColumnHelper<IWordForm>();
function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps) {
const textProcessor = useConceptText();
const { colors } = useConceptTheme();
const [term, setTerm] = useState('');
@ -65,32 +65,12 @@ function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
// Filter grammemes when input changes
useEffect(
() => {
let newFilter: GramData[] = [];
inputGrams.forEach(({value: gram}) => {
if (!newFilter.includes(gram)) {
if (NounGrams.includes(gram as Grammeme)) {
newFilter.push(...NounGrams);
}
if (VerbGrams.includes(gram as Grammeme)) {
newFilter.push(...VerbGrams);
}
}
});
inputGrams.forEach(({value: gram}) =>
GrammemeGroups.forEach(group => {
if (group.includes(gram as Grammeme)) {
newFilter = newFilter.filter(item => !group.includes(item as Grammeme) || item === gram);
}
}));
newFilter.push(...inputGrams.map(({value}) => value));
if (newFilter.length === 0) {
newFilter = [...VerbGrams, ...NounGrams];
}
newFilter = [... new Set(newFilter)];
setOptions(SelectorGrammems.filter(({value}) => newFilter.includes(value)));
const compatible = getCompatibleGrams(
inputGrams
.filter(data => Object.values(Grammeme).includes(data.value as Grammeme))
.map(data => data.value as Grammeme)
);
setOptions(SelectorGrammems.filter(({value}) => compatible.includes(value as Grammeme)));
}, [inputGrams]);
const handleSubmit = () => onSave(getData());
@ -329,4 +309,4 @@ function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
</Modal>);
}
export default DlgEditTerm;
export default DlgEditWordForms;

View File

@ -194,6 +194,7 @@ function EditorConstituenta({
<RefsInput id='term' label='Термин'
placeholder='Обозначение, используемое в текстовых определениях данной схемы'
height='3.5rem'
items={schema?.items}
value={term}
initialValue={activeCst?.term_raw ?? ''}
resolved={activeCst?.term_resolved ?? ''}
@ -221,6 +222,7 @@ function EditorConstituenta({
<RefsInput id='definition' label='Текстовое определение'
placeholder='Лингвистическая интерпретация формального выражения'
height='6.3rem'
items={schema?.items}
value={textDefinition}
initialValue={activeCst?.definition_raw ?? ''}
resolved={activeCst?.definition_resolved ?? ''}

View File

@ -21,7 +21,7 @@ import { createAliasFor } from '../../utils/misc';
import DlgCloneRSForm from './DlgCloneRSForm';
import DlgCreateCst from './DlgCreateCst';
import DlgDeleteCst from './DlgDeleteCst';
import DlgEditTerm from './DlgEditTerm';
import DlgEditWordForms from './DlgEditWordForms';
import DlgRenameCst from './DlgRenameCst';
import DlgShowAST from './DlgShowAST';
import DlgUploadRSForm from './DlgUploadRSForm';
@ -354,7 +354,7 @@ function RSTabs() {
selected={toBeDeleted}
/>}
{showEditTerm &&
<DlgEditTerm
<DlgEditWordForms
hideWindow={() => setShowEditTerm(false)}
onSave={handleSaveWordforms}
target={activeCst!}

View File

@ -244,6 +244,11 @@ export class CodeMirrorWrapper {
return this.ref.view.state.selection.main;
}
getSelectionText(): string {
const selection = this.getSelection();
return this.ref.view.state.doc.sliceString(selection.from, selection.to);
}
setSelection(from: number, to: number) {
this.ref.view.dispatch({
selection: {
@ -253,6 +258,10 @@ export class CodeMirrorWrapper {
});
}
insertChar(key: string) {
this.replaceWith(key);
}
replaceWith(data: string) {
this.ref.view.dispatch(this.ref.view.state.replaceSelection(data));
}
@ -274,8 +283,20 @@ export class CodeMirrorWrapper {
});
}
insertChar(key: string) {
this.replaceWith(key);
/**
* Access list of SyntaxNodes contained in current selection
*/
getContainedNodes(tokenFilter?: number[]): SyntaxNode[] {
const selection = this.getSelection();
return findContainedNodes(selection.from, selection.to, syntaxTree(this.ref.view.state), tokenFilter);
}
/**
* Access list of SyntaxNodes enveloping current selection
*/
getEnvelopingNodes(tokenFilter?: number[]): SyntaxNode[] {
const selection = this.getSelection();
return findEnvelopingNodes(selection.from, selection.to, syntaxTree(this.ref.view.state), tokenFilter);
}
/**

View File

@ -103,7 +103,7 @@ export const darkT: IColorTheme = {
fgGreen: 'hsl(100, 080%, 035%)',
fgBlue: 'hsl(235, 100%, 080%)',
fgPurple: 'hsl(270, 100%, 080%)',
fgTeal: 'hsl(192, 100%, 030%)',
fgTeal: 'hsl(192, 100%, 045%)',
fgOrange: 'hsl(035, 100%, 050%)'
};

View File

@ -36,5 +36,6 @@ export const prefixes = {
cst_list: 'cst-list-',
cst_status_list: 'cst-status-list-',
topic_list: 'topic-list-',
library_list: 'library-list-'
library_list: 'library-list-',
wordform_list: 'wordform-list'
}

View File

@ -1,6 +1,6 @@
// =========== Modules contains all text descriptors ==========
import { GramData,Grammeme } from '../models/language';
import { GramData,Grammeme, ReferenceType } from '../models/language';
import { CstMatchMode, DependencyMode, HelpTopic } from '../models/miscelanious';
import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform';
import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang';
@ -221,7 +221,7 @@ export function describeHelpTopic(topic: HelpTopic): string {
}
}
export function labelCstType(type: CstType) {
export function labelCstType(type: CstType): string {
switch (type) {
case CstType.BASE: return 'Базисное множество';
case CstType.CONSTANT: return 'Константное множество';
@ -234,6 +234,13 @@ export function labelCstType(type: CstType) {
}
}
export function labelReferenceType(type: ReferenceType): string {
switch(type) {
case ReferenceType.ENTITY: return 'Использование термина';
case ReferenceType.SYNTACTIC: return 'Синтаксическая зависимость';
}
}
export function labelCstClass(cclass: CstClass): string {
switch (cclass) {
case CstClass.BASIC: return 'базовый';

View File

@ -1,10 +1,10 @@
// Module: Selector maps
import { LayoutTypes } from 'reagraph';
import { compareGrammemes,type GramData, Grammeme } from '../models/language';
import { compareGrammemes,type GramData, Grammeme, ReferenceType } from '../models/language';
import { CstType } from '../models/rsform';
import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph';
import { labelGrammeme } from './labels';
import { labelGrammeme, labelReferenceType } from './labels';
import { labelCstType } from './labels';
/**
@ -79,3 +79,33 @@ gram => ({
value: gram,
label: labelGrammeme(gram)
}));
/**
* Represents options for {@link ReferenceType} selector.
*/
export const SelectorReferenceType = (
Object.values(ReferenceType)).map(
typeStr => ({
value: typeStr as ReferenceType,
label: labelReferenceType(typeStr as ReferenceType)
})
);
/**
* Represents recommended wordforms data.
*/
export const PremadeWordForms = [
{ text: 'ед им', example: 'ручка', grams: [Grammeme.sing, Grammeme.nomn] },
{ text: 'ед род', example: 'ручки', grams: [Grammeme.sing, Grammeme.gent] },
{ text: 'ед дат', example: 'ручке', grams: [Grammeme.sing, Grammeme.datv] },
{ text: 'ед вин', example: 'ручку', grams: [Grammeme.sing, Grammeme.accs] },
{ text: 'ед твор', example: 'ручкой', grams: [Grammeme.sing, Grammeme.ablt] },
{ text: 'ед пред', example: 'ручке', grams: [Grammeme.sing, Grammeme.loct] },
{ text: 'мн им', example: 'ручки', grams: [Grammeme.plur, Grammeme.nomn] },
{ text: 'мн род', example: 'ручек', grams: [Grammeme.plur, Grammeme.gent] },
{ text: 'мн дат', example: 'ручкам', grams: [Grammeme.plur, Grammeme.datv] },
{ text: 'мн вин', example: 'ручки', grams: [Grammeme.plur, Grammeme.accs] },
{ text: 'мн твор', example: 'ручками', grams: [Grammeme.plur, Grammeme.ablt] },
{ text: 'мн пред', example: 'ручках', grams: [Grammeme.plur, Grammeme.loct] }
];