add inflection on NPPronounPicker

This commit is contained in:
lingdocs 2022-04-23 12:40:42 +05:00
parent 2a6a4a9918
commit 5259305822
5 changed files with 56 additions and 28 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@lingdocs/pashto-inflector", "name": "@lingdocs/pashto-inflector",
"version": "2.1.8", "version": "2.1.9",
"author": "lingdocs.com", "author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com", "homepage": "https://verbs.lingdocs.com",

View File

@ -18,7 +18,7 @@ function NPPicker(props: {
onChange: (nps: T.NPSelection | undefined) => void, onChange: (nps: T.NPSelection | undefined) => void,
np: T.NPSelection | undefined, np: T.NPSelection | undefined,
counterPart: T.NPSelection | T.VerbObject | undefined, counterPart: T.NPSelection | T.VerbObject | undefined,
asObject?: boolean, role: "subject" | "object" | "ergative",
opts: T.TextOptions, opts: T.TextOptions,
cantClear?: boolean, cantClear?: boolean,
is2ndPersonPicker?: boolean, is2ndPersonPicker?: boolean,
@ -90,7 +90,7 @@ function NPPicker(props: {
</div>} </div>}
{(npType === "pronoun" && props.np?.type === "pronoun") {(npType === "pronoun" && props.np?.type === "pronoun")
? <PronounPicker ? <PronounPicker
asObject={props.asObject} role={props.role}
pronoun={props.np} pronoun={props.np}
onChange={props.onChange} onChange={props.onChange}
is2ndPersonPicker={props.is2ndPersonPicker} is2ndPersonPicker={props.is2ndPersonPicker}

View File

@ -3,7 +3,7 @@ import ButtonSelect from "../ButtonSelect";
import useStickyState from "../../lib/useStickyState"; import useStickyState from "../../lib/useStickyState";
import classNames from "classnames"; import classNames from "classnames";
import { import {
isSecondPerson, isThirdPerson, isSecondPerson,
} from "../../lib/phrase-building/vp-tools"; } from "../../lib/phrase-building/vp-tools";
const gColors = { const gColors = {
@ -11,13 +11,14 @@ const gColors = {
fem: "pink", fem: "pink",
}; };
const labels = (asObject: boolean) => ({ // TODO: better logic on this
persons: [ const labels = (role: "subject" | "object" | "ergative") => ({
["1st", "1st pl."], // persons: [
["2nd", "2nd pl."], // ["1st", "1st pl."],
["3rd", "3rd pl."], // ["2nd", "2nd pl."],
], // ["3rd", "3rd pl."],
e: asObject ? [ // ],
e: role === "object" ? [
["me", "us"], ["me", "us"],
["you", "you pl."], ["you", "you pl."],
[{ masc: "him/it", fem: "her/it"}, "them"], [{ masc: "him/it", fem: "her/it"}, "them"],
@ -26,7 +27,7 @@ const labels = (asObject: boolean) => ({
["You", "You pl."], ["You", "You pl."],
[{ masc: "He/It", fem: "She/It"}, "They"], [{ masc: "He/It", fem: "She/It"}, "They"],
], ],
p: { p: role === "subject" ? {
far: [ far: [
["زه", "مونږ"], ["زه", "مونږ"],
["ته", "تاسو"], ["ته", "تاسو"],
@ -37,6 +38,28 @@ const labels = (asObject: boolean) => ({
["ته", "تاسو"], ["ته", "تاسو"],
[{ masc: "دی", fem: "دا" }, "دوي"], [{ masc: "دی", fem: "دا" }, "دوي"],
], ],
} : role === "object" ? {
far: [
["زه", "مونږ"],
["ته", "تاسو"],
[{ masc: "هغهٔ", fem: "هغې" }, "هغوي"],
],
near: [
["زه", "مونږ"],
["ته", "تاسو"],
[{ masc: "دهٔ", fem: "دې" }, "دوي"],
],
} : {
far: [
["ما", "مونږ"],
["تا", "تاسو"],
[{ masc: "هغهٔ", fem: "هغې" }, "هغوي"],
],
near: [
["ما", "مونږ"],
["تا", "تاسو"],
[{ masc: "دهٔ", fem: "دې" }, "دوي"],
],
}, },
}); });
@ -56,10 +79,10 @@ function pickerStateToPerson(s: PickerState): T.Person {
+ (6 * s.col); + (6 * s.col);
} }
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2ndPersonPicker }: { function NPPronounPicker({ onChange, pronoun, role, clearButton, opts, is2ndPersonPicker }: {
pronoun: T.PronounSelection, pronoun: T.PronounSelection,
onChange: (p: T.PronounSelection) => void, onChange: (p: T.PronounSelection) => void,
asObject?: boolean, role: "object" | "subject" | "ergative",
clearButton?: JSX.Element, clearButton?: JSX.Element,
opts: T.TextOptions, opts: T.TextOptions,
is2ndPersonPicker?: boolean, is2ndPersonPicker?: boolean,
@ -67,7 +90,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
if (is2ndPersonPicker && !isSecondPerson(pronoun.person)) { if (is2ndPersonPicker && !isSecondPerson(pronoun.person)) {
throw new Error("can't use 2ndPerson NPProunounPicker without a pronoun"); throw new Error("can't use 2ndPerson NPProunounPicker without a pronoun");
} }
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display"); const [display, setDisplay] = useStickyState<"p" | "e">("e", "prounoun-picker-display2");
const p = personToPickerState(pronoun.person); const p = personToPickerState(pronoun.person);
function handleClick(row: number, col: number) { function handleClick(row: number, col: number) {
const person = pickerStateToPerson({ ...p, row, col }); const person = pickerStateToPerson({ ...p, row, col });
@ -90,21 +113,19 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
}); });
} }
function handleDisplayChange() { function handleDisplayChange() {
const newPerson = display === "persons" const newPerson = display === "p"
? "p"
: display === "p"
? "e" ? "e"
: "persons"; : "p";
setDisplay(newPerson); setDisplay(newPerson);
} }
const prs = labels(!!asObject)[display]; const prs = labels(role)[display];
const pSpecA = "near" in prs ? prs[pronoun.distance] : prs; const pSpecA = "near" in prs ? prs[pronoun.distance] : prs;
const pSpec = is2ndPersonPicker const pSpec = is2ndPersonPicker
? [pSpecA[1]] ? [pSpecA[1]]
: pSpecA; : pSpecA;
return <div style={{ maxWidth: "145px", padding: 0 }}> return <div style={{ maxWidth: "145px", padding: 0 }}>
<div className="d-flex flex-row justify-content-between mb-2"> <div className="d-flex flex-row justify-content-between mb-2">
{isThirdPerson(pronoun.person) ? <ButtonSelect <ButtonSelect
xSmall xSmall
options={[ options={[
{ label: "Far", value: "far" }, { label: "Far", value: "far" },
@ -112,9 +133,9 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
]} ]}
value={pronoun.distance} value={pronoun.distance}
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")} handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
/> : <div>{` `}</div>} />
<button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}> <button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}>
{display === "persons" ? "#" : display === "p" ? "PS" : "EN"} {display === "p" ? "PS" : display === "e" ? "PS" : "EN"}
</button> </button>
</div> </div>
<table className="table table-bordered table-sm" style={{ textAlign: "center", minWidth: "100px", tableLayout: "fixed" }}> <table className="table table-bordered table-sm" style={{ textAlign: "center", minWidth: "100px", tableLayout: "fixed" }}>
@ -125,6 +146,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
const active = is2ndPersonPicker const active = is2ndPersonPicker
? (p.col === j) ? (p.col === j)
: (p.row === i && p.col === j); : (p.row === i && p.col === j);
const content = typeof r === "string" ? r : r[p.gender];
return <td return <td
onClick={() => { onClick={() => {
handleClick(is2ndPersonPicker ? 1 : i, j); handleClick(is2ndPersonPicker ? 1 : i, j);
@ -136,7 +158,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
}} }}
> >
<div className="my-1"> <div className="my-1">
{typeof r === "string" ? r : r[p.gender]} {content}
</div> </div>
</td>; </td>;
})} })}

View File

@ -224,11 +224,12 @@ function TensePicker(props: ({
: verbTenseOptions; : verbTenseOptions;
const showImperativeOption = ("vps" in props && props.vps.verb.voice === "active") const showImperativeOption = ("vps" in props && props.vps.verb.voice === "active")
|| ("vpsComplete" in props && props.vpsComplete.verb.voice !== "active"); || ("vpsComplete" in props && props.vpsComplete.verb.voice !== "active");
const canHaveFormula = "vps" in props && props.vps.verb.voice === "active";
return <div> return <div>
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}> <div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
<div className="d-flex flex-row justify-content-between align-items-center"> <div className="d-flex flex-row justify-content-between align-items-center">
<div className="h5">Tense:</div> <div className="h5">Tense:</div>
{"vps" in props && <div className="clickable mb-2 small" onClick={() => setShowFormula(x => !x)}> {canHaveFormula && <div className="clickable mb-2 small" onClick={() => setShowFormula(x => !x)}>
🧪 {!showFormula ? "Show" : "Hide"} Formula 🧪 {!showFormula ? "Show" : "Hide"} Formula
</div>} </div>}
</div> </div>
@ -305,7 +306,7 @@ function TensePicker(props: ({
<i className="fas fa-chevron-right" /> <i className="fas fa-chevron-right" />
</div> </div>
</div>} </div>}
{("vps" in props && showFormula) && (() => { {(canHaveFormula && showFormula) && (() => {
// TODO: Be able to show modal formulas too // TODO: Be able to show modal formulas too
const curr = (props.vps.verb.tenseCategory === "imperative" && props.vps.verb.negative) const curr = (props.vps.verb.tenseCategory === "imperative" && props.vps.verb.negative)
? imperativeTenseOptions.find(x => x.value === "imperfectiveImperative") ? imperativeTenseOptions.find(x => x.value === "imperfectiveImperative")

View File

@ -63,8 +63,9 @@ export function VPExplorer(props: {
"verbExplorerMode", "verbExplorerMode",
); );
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false); const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense);
const roles = getKingAndServant( const roles = getKingAndServant(
isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense), isPast,
vps.verb.transitivity !== "intransitive", vps.verb.transitivity !== "intransitive",
); );
useEffect(() => { useEffect(() => {
@ -158,6 +159,10 @@ export function VPExplorer(props: {
nouns: props.nouns, nouns: props.nouns,
verbs: props.verbs, verbs: props.verbs,
}} }}
role={(isPast && vps.verb.transitivity !== "intransitive")
? "ergative"
: "subject"
}
is2ndPersonPicker={vps.verb.tenseCategory === "imperative"} is2ndPersonPicker={vps.verb.tenseCategory === "imperative"}
np={vps.subject} np={vps.subject}
counterPart={vps.verb ? vps.verb.object : undefined} counterPart={vps.verb ? vps.verb.object : undefined}
@ -181,7 +186,7 @@ export function VPExplorer(props: {
nouns: props.nouns, nouns: props.nouns,
verbs: props.verbs, verbs: props.verbs,
}} }}
asObject role="object"
np={vps.verb.object} np={vps.verb.object}
counterPart={vps.subject} counterPart={vps.subject}
onChange={handleObjectChange} onChange={handleObjectChange}