From 10532cb3bbb7d6c5969b63aae6ec920efadd26ac Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 20 Apr 2022 19:05:15 +0500 Subject: [PATCH] include imperative --- package.json | 2 +- src/App.tsx | 1 - src/components/Examples.tsx | 1 - src/components/VerbFormDisplay.tsx | 2 +- src/components/np-picker/NPPicker.tsx | 6 + src/components/np-picker/NPPronounPicker.tsx | 29 +++-- src/components/vp-explorer/ChartDisplay.tsx | 2 +- src/components/vp-explorer/TensePicker.tsx | 116 +++++++++++++----- src/components/vp-explorer/VPExplorer.tsx | 17 ++- src/components/vp-explorer/VPExplorerQuiz.tsx | 4 +- src/components/vp-explorer/verb-selection.ts | 1 + src/lib/irregular-conjugations.ts | 3 + src/lib/phrase-building/compile-vp.ts | 6 +- .../phrase-building/english-vp-rendering.ts | 14 +++ src/lib/phrase-building/render-vp.ts | 19 ++- src/lib/phrase-building/vp-tools.ts | 116 +++++++++++++++++- src/lib/type-predicates.ts | 11 +- src/lib/verb-conjugation.ts | 34 +++-- src/types.ts | 28 ++--- 19 files changed, 310 insertions(+), 102 deletions(-) diff --git a/package.json b/package.json index 9fe489e..a60eab8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "2.1.2", + "version": "2.1.3", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/App.tsx b/src/App.tsx index edd6ff9..5de9ce6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -69,7 +69,6 @@ function App() { }, [theme]) const handleVerbIndexChange = (e: any) => { - console.log("changing to", e.target.value); setVerbTs(parseInt(e.target.value)); } const handleTypeSelection = (e: any) => { diff --git a/src/components/Examples.tsx b/src/components/Examples.tsx index 2901269..bcacf99 100644 --- a/src/components/Examples.tsx +++ b/src/components/Examples.tsx @@ -14,7 +14,6 @@ type PsStringWSub = T.PsString & { sub?: any }; function EnglishContent({ children }: { children: (string | JSX.Element)[] | (string | JSX.Element) }) { if (Array.isArray(children)) { - console.log(children); return <> {children.map((x) => {x})} diff --git a/src/components/VerbFormDisplay.tsx b/src/components/VerbFormDisplay.tsx index 9d5d20e..5241b9b 100644 --- a/src/components/VerbFormDisplay.tsx +++ b/src/components/VerbFormDisplay.tsx @@ -40,7 +40,7 @@ function agreementInfo(info: T.NonComboVerbInfo, displayForm: T.DisplayForm): Re } function VerbFormDisplay({ displayForm, textOptions, info, showingFormInfo, english, shortDefault }: { - displayForm: T.DisplayForm | T.VerbForm, + displayForm: T.DisplayForm | T.VerbForm | T.ImperativeForm, english?: T.EnglishBlock | string, textOptions: T.TextOptions, showingFormInfo: boolean, diff --git a/src/components/np-picker/NPPicker.tsx b/src/components/np-picker/NPPicker.tsx index e4fff67..dfb3f99 100644 --- a/src/components/np-picker/NPPicker.tsx +++ b/src/components/np-picker/NPPicker.tsx @@ -8,6 +8,7 @@ import { } from "../../lib/np-tools"; import { useState, useEffect } from "react"; import * as T from "../../types"; +import { isSecondPerson } from "../../lib/phrase-building/vp-tools"; // import { capitalizeFirstLetter } from "../../lib/text-tools"; const npTypes: T.NPType[] = ["pronoun", "noun", "participle"]; @@ -19,6 +20,7 @@ function NPPicker(props: { asObject?: boolean, opts: T.TextOptions, cantClear?: boolean, + is2ndPersonPicker?: boolean, } & ({ nouns: (s: string) => T.NounEntry[], verbs: (s: string) => T.VerbEntry[], @@ -28,6 +30,9 @@ function NPPicker(props: { nouns: T.NounEntry[], verbs: T.VerbEntry[], })) { + if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) { + throw new Error("can't use 2ndPerson NPPicker without a pronoun"); + } const [npType, setNpType] = useState(props.np ? props.np.type : undefined); useEffect(() => { setNpType(props.np ? props.np.type : undefined); @@ -78,6 +83,7 @@ function NPPicker(props: { pronoun={props.np} onChange={props.onChange} clearButton={clearButton} + is2ndPersonPicker={props.is2ndPersonPicker} opts={props.opts} /> : npType === "noun" diff --git a/src/components/np-picker/NPPronounPicker.tsx b/src/components/np-picker/NPPronounPicker.tsx index 23ee7db..bffd930 100644 --- a/src/components/np-picker/NPPronounPicker.tsx +++ b/src/components/np-picker/NPPronounPicker.tsx @@ -2,6 +2,9 @@ import * as T from "../../types"; import ButtonSelect from "../ButtonSelect"; import useStickyState from "../../lib/useStickyState"; import classNames from "classnames"; +import { + isSecondPerson, isThirdPerson, +} from "../../lib/phrase-building/vp-tools"; const gColors = { masc: "LightSkyBlue", @@ -53,15 +56,18 @@ function pickerStateToPerson(s: PickerState): T.Person { + (6 * s.col); } -function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: { +function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2ndPersonPicker }: { pronoun: T.PronounSelection, onChange: (p: T.PronounSelection) => void, asObject?: boolean, clearButton?: JSX.Element, opts: T.TextOptions, + is2ndPersonPicker?: boolean, }) { + if (is2ndPersonPicker && !isSecondPerson(pronoun.person)) { + throw new Error("can't use 2ndPerson NPProunounPicker without a pronoun"); + } const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display"); - const p = personToPickerState(pronoun.person); function handleClick(row: number, col: number) { const person = pickerStateToPerson({ ...p, row, col }); @@ -92,11 +98,14 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: { setDisplay(newPerson); } const prs = labels(!!asObject)[display]; - const pSpec = "near" in prs ? prs[pronoun.distance] : prs; + const pSpecA = "near" in prs ? prs[pronoun.distance] : prs; + const pSpec = is2ndPersonPicker + ? [pSpecA[1]] + : pSpecA; return
{clearButton} -
- + {isThirdPerson(pronoun.person) ? handlePronounTypeChange(g as "far" | "near")} - /> + /> :
{` `}
} @@ -114,9 +123,13 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: { {pSpec.map((rw, i) => ( {rw.map((r, j) => { - const active = (p.row === i && p.col === j) + const active = is2ndPersonPicker + ? (p.col === j) + : (p.row === i && p.col === j); return handleClick(i, j)} + onClick={() => { + handleClick(is2ndPersonPicker ? 1 : i, j); + }} className={classNames({ "table-active": active, "text-on-gender-color": active })} style={{ backgroundColor: active ? gColors[p.gender] : "inherit", diff --git a/src/components/vp-explorer/ChartDisplay.tsx b/src/components/vp-explorer/ChartDisplay.tsx index c610798..039c4c4 100644 --- a/src/components/vp-explorer/ChartDisplay.tsx +++ b/src/components/vp-explorer/ChartDisplay.tsx @@ -16,7 +16,7 @@ function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions } : ("transitive" in rawConjugations) ? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"] : rawConjugations; - const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice); + const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice, VS.negative); return
present
, @@ -55,8 +56,16 @@ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense value: "pastSubjunctivePerfect", }]; -export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): T.PerfectTense | T.VerbTense | T.ModalTense { - let tns: T.PerfectTense | T.VerbTense | T.ModalTense; +const imperativeTenseOptions: { label: string | JSX.Element, value: T.ImperativeTense }[] = [{ + label:
imperfective imp.
, + value: "imperfectiveImperative", +}, { + label:
perfective imp.
, + value: "perfectiveImperative", +}]; + +export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense): T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense { + let tns: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense; const oldTenseCategory = !o ? undefined : getTenseCategory(o); @@ -64,6 +73,8 @@ export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): ? perfectTenseOptions : oldTenseCategory === "modal" ? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense })) + : oldTenseCategory === "imperative" + ? imperativeTenseOptions : verbTenseOptions; do { tns = tenseOptions[ @@ -81,7 +92,7 @@ function TensePicker(props: ({ onChange: (p: T.VPSelection) => void, mode: "charts" | "phrases" | "quiz", }) { - function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) { + function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense | T.ImperativeTense } | null) { if ("vpsComplete" in props) return; const value = o?.value ? o.value : undefined; if (props.vps.verb && value) { @@ -94,6 +105,15 @@ function TensePicker(props: ({ tenseCategory: "perfect", }, }); + } else if (isImperativeTense(value)) { + props.onChange({ + ...props.vps, + verb: { + ...props.vps.verb, + imperativeTense: value, + tenseCategory: "imperative", + }, + }); } else { props.onChange({ ...props.vps, @@ -112,9 +132,19 @@ function TensePicker(props: ({ if ("vpsComplete" in props) return; if (!props.vps.verb) return; return () => { - const tenses = props.vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions; + // TODO: ABSTRACT THIS - SAFER + const tenses = props.vps.verb.tenseCategory === "perfect" + ? perfectTenseOptions + : props.vps.verb.tenseCategory === "imperative" + ? imperativeTenseOptions + : verbTenseOptions; const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[ - props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense" + // TODO: ABSTRACT THIS? - SAFER + props.vps.verb.tenseCategory === "perfect" + ? "perfectTense" + : props.vps.verb.tenseCategory === "imperative" + ? "imperativeTense" + : "verbTense" ]); if (currIndex === -1) { console.error("error moving tense", dir); @@ -139,9 +169,19 @@ function TensePicker(props: ({ }); } } - function onTenseCategorySelect(value: "basic" | "modal" | "perfect") { + function onTenseCategorySelect(value: "basic" | "modal" | "perfect" | "imperative") { if ("vpsComplete" in props) return; if (props.vps.verb) { + if (value === "imperative") { + props.onChange(ensure2ndPersSubjPronounAndNoConflict({ + ...props.vps, + verb: { + ...props.vps.verb, + tenseCategory: value, + }, + })); + return; + } props.onChange({ ...props.vps, verb: { @@ -153,40 +193,47 @@ function TensePicker(props: ({ } const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect")) ? perfectTenseOptions + : ("vps" in props && (props.vps.verb?.tenseCategory === "imperative")) + ? imperativeTenseOptions : verbTenseOptions; return
-
-
Tense:
- {("vpsComplete" in props || props.vps.verb) &&
- null} - /> -
} -
+
Tense:
+ {("vpsComplete" in props || props.vps.verb) &&
+ null} + /> +
} {"vpsComplete" in props ?
- {[...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label} + {[...verbTenseOptions, ...perfectTenseOptions, ...imperativeTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label}
: