refactoring to allow for dictionary lookup in phrase builder
This commit is contained in:
parent
8191b48f05
commit
759df4811e
|
@ -13,7 +13,7 @@ function EntrySelect<E extends T.DictionaryEntry | VerbEntry>(props: ({
|
|||
entries: E[]
|
||||
} | {
|
||||
searchF: (search: string) => E[],
|
||||
getByTs: (ts: number) => E,
|
||||
getByTs: (ts: number) => E | undefined,
|
||||
}) & {
|
||||
value: E | undefined,
|
||||
onChange: (value: E | undefined) => void,
|
||||
|
|
|
@ -6,83 +6,93 @@ import {
|
|||
InlinePs,
|
||||
Types as T,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import { useState } from "react";
|
||||
import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
||||
// import { useState } from "react";
|
||||
// import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
||||
import EntrySelect from "../EntrySelect";
|
||||
|
||||
const filterOptions = [
|
||||
{
|
||||
label: "1",
|
||||
value: "1",
|
||||
},
|
||||
{
|
||||
label: "2",
|
||||
value: "2",
|
||||
},
|
||||
{
|
||||
label: "3",
|
||||
value: "3",
|
||||
},
|
||||
{
|
||||
label: "4",
|
||||
value: "4",
|
||||
},
|
||||
{
|
||||
label: "5",
|
||||
value: "5",
|
||||
},
|
||||
{
|
||||
label: "6",
|
||||
value: "6",
|
||||
},
|
||||
];
|
||||
// const filterOptions = [
|
||||
// {
|
||||
// label: "1",
|
||||
// value: "1",
|
||||
// },
|
||||
// {
|
||||
// label: "2",
|
||||
// value: "2",
|
||||
// },
|
||||
// {
|
||||
// label: "3",
|
||||
// value: "3",
|
||||
// },
|
||||
// {
|
||||
// label: "4",
|
||||
// value: "4",
|
||||
// },
|
||||
// {
|
||||
// label: "5",
|
||||
// value: "5",
|
||||
// },
|
||||
// {
|
||||
// label: "6",
|
||||
// value: "6",
|
||||
// },
|
||||
// ];
|
||||
|
||||
type FilterPattern = "1" | "2" | "3" | "4" | "5" | "6";
|
||||
// type FilterPattern = "1" | "2" | "3" | "4" | "5" | "6";
|
||||
|
||||
function nounFilter(p: FilterPattern | undefined) {
|
||||
return p === undefined
|
||||
? () => true
|
||||
: (p === "1")
|
||||
? isPattern1Entry
|
||||
: (p === "2")
|
||||
? isPattern2Entry
|
||||
: (p === "3")
|
||||
? isPattern3Entry
|
||||
: (p === "4")
|
||||
? isPattern4Entry
|
||||
: (p === "5")
|
||||
? isPattern5Entry
|
||||
: (p === "6")
|
||||
? (n: NounEntry) => (isFemNounEntry(n) && isPattern6FemEntry(n))
|
||||
: () => true;
|
||||
}
|
||||
// function nounFilter(p: FilterPattern | undefined) {
|
||||
// return p === undefined
|
||||
// ? () => true
|
||||
// : (p === "1")
|
||||
// ? isPattern1Entry
|
||||
// : (p === "2")
|
||||
// ? isPattern2Entry
|
||||
// : (p === "3")
|
||||
// ? isPattern3Entry
|
||||
// : (p === "4")
|
||||
// ? isPattern4Entry
|
||||
// : (p === "5")
|
||||
// ? isPattern5Entry
|
||||
// : (p === "6")
|
||||
// ? (n: NounEntry) => (isFemNounEntry(n) && isPattern6FemEntry(n))
|
||||
// : () => true;
|
||||
// }
|
||||
|
||||
function NPNounPicker({ onChange, noun, nouns, clearButton, opts }: { nouns: NounEntry[], noun: NounSelection | undefined, onChange: (p: NounSelection | undefined) => void, clearButton?: JSX.Element, opts: T.TextOptions }) {
|
||||
const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||
const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||
const nounsFiltered = nouns
|
||||
.filter(nounFilter(patternFilter))
|
||||
.sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
|
||||
function NPNounPicker(props: ({
|
||||
nouns: NounEntry[],
|
||||
} | {
|
||||
nouns: (s: string) => NounEntry[],
|
||||
getNounByTs: (ts: number) => NounEntry | undefined;
|
||||
}) & {
|
||||
noun: NounSelection | undefined,
|
||||
onChange: (p: NounSelection | undefined) => void,
|
||||
clearButton?: JSX.Element,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||
// const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||
// const nounsFiltered = props.nouns
|
||||
// .filter(nounFilter(patternFilter))
|
||||
// .sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
|
||||
function onEntrySelect(entry: NounEntry | undefined) {
|
||||
if (!entry) {
|
||||
return onChange(undefined);
|
||||
return props.onChange(undefined);
|
||||
}
|
||||
onChange(makeNounSelection(entry));
|
||||
}
|
||||
function handleFilterClose() {
|
||||
setPatternFilter(undefined);
|
||||
setShowFilter(false);
|
||||
props.onChange(makeNounSelection(entry));
|
||||
}
|
||||
// function handleFilterClose() {
|
||||
// setPatternFilter(undefined);
|
||||
// setShowFilter(false);
|
||||
// }
|
||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
{clearButton}
|
||||
{(!showFilter && !(noun?.dynamicComplement)) && <div className="text-right">
|
||||
<div className="d-flex flex-row justify-content-left">
|
||||
{props.clearButton}
|
||||
{/* {(!showFilter && !(noun?.dynamicComplement)) && <div className="text-right">
|
||||
<button className="btn btn-sm btn-light mb-2 text-small" onClick={() => setShowFilter(true)}>
|
||||
<i className="fas fa-filter fa-xs" />
|
||||
</button>
|
||||
</div>}
|
||||
</div>} */}
|
||||
</div>
|
||||
{showFilter && <div className="mb-2 text-center">
|
||||
{/* {showFilter && <div className="mb-2 text-center">
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div className="text-small mb-1">Filter by inflection pattern</div>
|
||||
<div className="clickable" onClick={handleFilterClose}>X</div>
|
||||
|
@ -94,54 +104,59 @@ function NPNounPicker({ onChange, noun, nouns, clearButton, opts }: { nouns: Nou
|
|||
// @ts-ignore
|
||||
handleChange={setPatternFilter}
|
||||
/>
|
||||
</div>}
|
||||
{!(noun && noun.dynamicComplement) ? <div>
|
||||
</div>} */}
|
||||
{!(props.noun && props.noun.dynamicComplement) ? <div>
|
||||
<EntrySelect
|
||||
value={noun?.entry}
|
||||
entries={nounsFiltered}
|
||||
value={props.noun?.entry}
|
||||
{..."getNounByTs" in props ? {
|
||||
getByTs: props.getNounByTs,
|
||||
searchF: props.nouns
|
||||
} : {
|
||||
entries: props.nouns,
|
||||
}}
|
||||
onChange={onEntrySelect}
|
||||
name="Noun"
|
||||
opts={opts}
|
||||
opts={props.opts}
|
||||
/>
|
||||
</div> : <div>
|
||||
{noun && <div>
|
||||
{props.noun && <div>
|
||||
<div className="mb-2">Included in Dyn. Compound:</div>
|
||||
<div className="mb-3 text-center">
|
||||
<InlinePs opts={opts}>
|
||||
{{ p: noun.entry.p, f: noun.entry.f }}
|
||||
<InlinePs opts={props.opts}>
|
||||
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
|
||||
</InlinePs>
|
||||
<div className="text-muted">{noun.entry.e}</div>
|
||||
<div className="text-muted">{props.noun.entry.e}</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>}
|
||||
{noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>
|
||||
{noun.changeGender ? <ButtonSelect
|
||||
{props.noun.changeGender ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Masc", value: "masc" },
|
||||
{ label: "Fem", value: "fem" },
|
||||
]}
|
||||
value={noun.gender}
|
||||
value={props.noun.gender}
|
||||
handleChange={(g) => {
|
||||
if (!noun.changeGender) return;
|
||||
onChange(noun.changeGender(g));
|
||||
if (!props.noun || !props.noun.changeGender) return;
|
||||
props.onChange(props.noun.changeGender(g));
|
||||
}}
|
||||
/> : noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
</div>
|
||||
<div>
|
||||
{noun.changeNumber ? <ButtonSelect
|
||||
{props.noun.changeNumber ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Sing.", value: "singular" },
|
||||
{ label: "Plur.", value: "plural" },
|
||||
]}
|
||||
value={noun.number}
|
||||
value={props.noun.number}
|
||||
handleChange={(n) => {
|
||||
if (!noun.changeNumber) return;
|
||||
onChange(noun.changeNumber(n));
|
||||
if (!props.noun || !props.noun.changeNumber) return;
|
||||
props.onChange(props.noun.changeNumber(n));
|
||||
}}
|
||||
/> : noun.number === "singular" ? "Sing." : "Plur."}
|
||||
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
|
||||
</div>
|
||||
</div>}
|
||||
</div>;
|
||||
|
|
|
@ -10,8 +10,12 @@ function makeParticipleSelection(verb: VerbEntry): ParticipleSelection {
|
|||
};
|
||||
}
|
||||
|
||||
function NPParticiplePicker({ onChange, participle, verbs, clearButton, opts }: {
|
||||
function NPParticiplePicker(props: ({
|
||||
verbs: VerbEntry[],
|
||||
} | {
|
||||
verbs: (s: string) => VerbEntry[],
|
||||
getVerbByTs: (ts: number) => VerbEntry | undefined;
|
||||
}) & {
|
||||
participle: ParticipleSelection | undefined,
|
||||
onChange: (p: ParticipleSelection | undefined) => void,
|
||||
clearButton: JSX.Element,
|
||||
|
@ -19,21 +23,26 @@ function NPParticiplePicker({ onChange, participle, verbs, clearButton, opts }:
|
|||
}) {
|
||||
function onEntrySelect(entry: VerbEntry | undefined) {
|
||||
if (!entry) {
|
||||
onChange(undefined);
|
||||
props.onChange(undefined);
|
||||
return;
|
||||
}
|
||||
onChange(makeParticipleSelection(entry));
|
||||
props.onChange(makeParticipleSelection(entry));
|
||||
}
|
||||
return <div style={{ maxWidth: "225px" }}>
|
||||
{clearButton}
|
||||
{props.clearButton}
|
||||
<EntrySelect
|
||||
value={participle?.verb}
|
||||
entries={verbs}
|
||||
value={props.participle?.verb}
|
||||
{..."getVerbByTs" in props ? {
|
||||
getByTs: props.getVerbByTs,
|
||||
searchF: props.verbs,
|
||||
} : {
|
||||
entries: props.verbs,
|
||||
}}
|
||||
onChange={onEntrySelect}
|
||||
name="Pariticple"
|
||||
opts={opts}
|
||||
opts={props.opts}
|
||||
/>
|
||||
{participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
{props.participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>Masc.</div>
|
||||
<div>Plur.</div>
|
||||
</div>}
|
||||
|
|
|
@ -5,7 +5,6 @@ import ParticiplePicker from "./NPParticiplePicker";
|
|||
// import { ButtonSelect } from "@lingdocs/pashto-inflector";
|
||||
import { randomPerson } from "../../lib/np-tools";
|
||||
import { useState, useEffect } from "react";
|
||||
import { nouns, verbs } from "../../words/words";
|
||||
import {
|
||||
Types as T,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
@ -13,38 +12,46 @@ import {
|
|||
|
||||
const npTypes: NPType[] = ["pronoun", "noun", "participle"];
|
||||
|
||||
function NPPicker({ np, onChange, counterPart, asObject, opts }: {
|
||||
function NPPicker(props: {
|
||||
onChange: (nps: NPSelection | undefined) => void,
|
||||
np: NPSelection | undefined,
|
||||
counterPart: NPSelection | VerbObject | undefined,
|
||||
asObject?: boolean,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
const [npType, setNpType] = useState<NPType | undefined>(np ? np.type : undefined);
|
||||
} & ({
|
||||
nouns: (s: string) => NounEntry[],
|
||||
verbs: (s: string) => VerbEntry[],
|
||||
getNounByTs: (ts: number) => NounEntry | undefined,
|
||||
getVerbByTs: (ts: number) => VerbEntry | undefined,
|
||||
} | {
|
||||
nouns: NounEntry[],
|
||||
verbs: VerbEntry[],
|
||||
})) {
|
||||
const [npType, setNpType] = useState<NPType | undefined>(props.np ? props.np.type : undefined);
|
||||
useEffect(() => {
|
||||
setNpType(np ? np.type : undefined);
|
||||
}, [np]);
|
||||
setNpType(props.np ? props.np.type : undefined);
|
||||
}, [props.np]);
|
||||
function handleClear() {
|
||||
if (np && np.type === "noun" && np.dynamicComplement) return;
|
||||
if (props.np && props.np.type === "noun" && props.np.dynamicComplement) return;
|
||||
setNpType(undefined);
|
||||
onChange(undefined);
|
||||
props.onChange(undefined);
|
||||
}
|
||||
function handleNPTypeChange(ntp: NPType) {
|
||||
if (ntp === "pronoun") {
|
||||
const person = randomPerson({ counterPart });
|
||||
const person = randomPerson({ counterPart: props.counterPart });
|
||||
const pronoun: PronounSelection = {
|
||||
type: "pronoun",
|
||||
person,
|
||||
distance: "far",
|
||||
};
|
||||
setNpType(ntp);
|
||||
onChange(pronoun);
|
||||
props.onChange(pronoun);
|
||||
} else {
|
||||
onChange(undefined);
|
||||
props.onChange(undefined);
|
||||
setNpType(ntp);
|
||||
}
|
||||
}
|
||||
const isDynamicComplement = np && np.type === "noun" && np.dynamicComplement;
|
||||
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
|
||||
const clearButton = <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>;
|
||||
return <div>
|
||||
{!npType && <div className="text-center mt-3">
|
||||
|
@ -62,29 +69,39 @@ function NPPicker({ np, onChange, counterPart, asObject, opts }: {
|
|||
</button>
|
||||
</div>)}
|
||||
</div>}
|
||||
{(npType === "pronoun" && np?.type === "pronoun")
|
||||
{(npType === "pronoun" && props.np?.type === "pronoun")
|
||||
? <PronounPicker
|
||||
asObject={asObject}
|
||||
pronoun={np}
|
||||
onChange={onChange}
|
||||
asObject={props.asObject}
|
||||
pronoun={props.np}
|
||||
onChange={props.onChange}
|
||||
clearButton={clearButton}
|
||||
opts={opts}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: npType === "noun"
|
||||
? <NounPicker
|
||||
nouns={nouns}
|
||||
noun={(np && np.type === "noun") ? np : undefined}
|
||||
onChange={onChange}
|
||||
{..."getNounByTs" in props ? {
|
||||
nouns: props.nouns,
|
||||
getNounByTs: props.getNounByTs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
}}
|
||||
noun={(props.np && props.np.type === "noun") ? props.np : undefined}
|
||||
onChange={props.onChange}
|
||||
clearButton={!isDynamicComplement ? clearButton : undefined}
|
||||
opts={opts}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: npType === "participle"
|
||||
? <ParticiplePicker
|
||||
verbs={verbs}
|
||||
participle={(np && np.type === "participle") ? np : undefined}
|
||||
onChange={onChange}
|
||||
{..."getVerbByTs" in props ? {
|
||||
verbs: props.verbs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
} : {
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
participle={(props.np && props.np.type === "participle") ? props.np : undefined}
|
||||
onChange={props.onChange}
|
||||
clearButton={clearButton}
|
||||
opts={opts}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: null
|
||||
}
|
||||
|
|
|
@ -33,8 +33,16 @@ const servantEmoji = "🙇♂️";
|
|||
// TODO: error handling on error with rendering etc
|
||||
export function PhraseBuilder(props: {
|
||||
verb?: VerbEntry,
|
||||
opts?: T.TextOptions,
|
||||
}) {
|
||||
opts: T.TextOptions,
|
||||
} & ({
|
||||
nouns: NounEntry[],
|
||||
verbs: VerbEntry[],
|
||||
} | {
|
||||
nouns: (s: string) => NounEntry[],
|
||||
verbs: (s: string) => VerbEntry[],
|
||||
getNounByTs: (ts: number) => NounEntry | undefined,
|
||||
getVerbByTs: (ts: number) => VerbEntry | undefined,
|
||||
})) {
|
||||
const [subject, setSubject] = useStickyState<NPSelection | undefined>(undefined, "subjectNPSelection");
|
||||
const [mode, setMode] = useStickyState<"charts" | "phrases">("phrases", "verbExplorerMode");
|
||||
const passedVerb = props.verb;
|
||||
|
@ -101,6 +109,15 @@ export function PhraseBuilder(props: {
|
|||
<div className="my-2">
|
||||
<div className="h5 text-center">Subject {showRole(VPRendered, "subject")}</div>
|
||||
<NPPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
getNounByTs: props.getNounByTs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
np={subject}
|
||||
counterPart={verb ? verb.object : undefined}
|
||||
onChange={handleSubjectChange}
|
||||
|
@ -112,6 +129,15 @@ export function PhraseBuilder(props: {
|
|||
{(typeof verb.object === "number")
|
||||
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
||||
: <NPPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
getNounByTs: props.getNounByTs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
asObject
|
||||
np={verb.object}
|
||||
counterPart={subject}
|
||||
|
|
|
@ -4,5 +4,13 @@ fullWidth: true
|
|||
---
|
||||
|
||||
import PhraseBuilder from "../../components/phrase-builder/PhraseBuilder";
|
||||
import {
|
||||
defaultTextOptions,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import { nouns, verbs } from "../../words/words";
|
||||
|
||||
<PhraseBuilder />
|
||||
<PhraseBuilder
|
||||
opts={defaultTextOptions}
|
||||
nouns={nouns}
|
||||
verbs={verbs}
|
||||
/>
|
Loading…
Reference in New Issue