abstracted proper entry picker component - ugly inside, nice on outside
This commit is contained in:
parent
03c7a8ba02
commit
f1dd160b53
|
@ -0,0 +1,67 @@
|
||||||
|
import {
|
||||||
|
Types as T,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import Select from "react-select";
|
||||||
|
import {
|
||||||
|
makeSelectOption,
|
||||||
|
makeVerbSelectOption,
|
||||||
|
zIndexProps,
|
||||||
|
} from "./np-picker/picker-tools";
|
||||||
|
|
||||||
|
function EntrySelect<E extends T.DictionaryEntry | VerbEntry>(props: {
|
||||||
|
entries: E[],
|
||||||
|
value: E | undefined,
|
||||||
|
onChange: (value: E | undefined) => void,
|
||||||
|
name: string | undefined,
|
||||||
|
isVerbSelect?: boolean,
|
||||||
|
}) {
|
||||||
|
const options = props.entries
|
||||||
|
.sort((a, b) => {
|
||||||
|
if ("entry" in a) {
|
||||||
|
return a.entry.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS")
|
||||||
|
}
|
||||||
|
return a.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS");
|
||||||
|
})
|
||||||
|
.map((e) => {
|
||||||
|
if ("entry" in e) {
|
||||||
|
return (props.isVerbSelect ? makeVerbSelectOption : makeSelectOption)(e);
|
||||||
|
}
|
||||||
|
return makeSelectOption(e);
|
||||||
|
});
|
||||||
|
function onSelect(v: { label: string, value: string } | null) {
|
||||||
|
if (!v) {
|
||||||
|
props.onChange(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const s = props.entries.find(e => (
|
||||||
|
("entry" in e)
|
||||||
|
? e.entry.ts.toString() === v.value
|
||||||
|
: e.ts.toString() === v.value
|
||||||
|
));
|
||||||
|
if (!s) return;
|
||||||
|
props.onChange(s);
|
||||||
|
}
|
||||||
|
const selectedEntry: T.DictionaryEntry | undefined = !props.value
|
||||||
|
? undefined
|
||||||
|
: "entry" in props.value
|
||||||
|
? props.value.entry
|
||||||
|
: "p" in props.value
|
||||||
|
? props.value
|
||||||
|
: undefined;
|
||||||
|
const selected = !selectedEntry
|
||||||
|
? undefined
|
||||||
|
: options.find(o => (selectedEntry && (o.value === selectedEntry.ts.toString())));
|
||||||
|
return <div>
|
||||||
|
<Select
|
||||||
|
isSearchable={true}
|
||||||
|
value={selected}
|
||||||
|
onChange={onSelect}
|
||||||
|
className="mb-2"
|
||||||
|
options={options}
|
||||||
|
placeholder={props.name ? `Select ${props.name}...` : undefined}
|
||||||
|
{...zIndexProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EntrySelect;
|
|
@ -1,7 +1,6 @@
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import {
|
import {
|
||||||
makeNounSelection,
|
makeNounSelection,
|
||||||
makeVerbSelectOption,
|
|
||||||
zIndexProps,
|
zIndexProps,
|
||||||
} from "./np-picker/picker-tools";
|
} from "./np-picker/picker-tools";
|
||||||
import {
|
import {
|
||||||
|
@ -10,6 +9,7 @@ import {
|
||||||
getVerbInfo,
|
getVerbInfo,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
import { isPerfectTense } from "../lib/phrase-building/vp-tools";
|
import { isPerfectTense } from "../lib/phrase-building/vp-tools";
|
||||||
|
import EntrySelect from "./EntrySelect";
|
||||||
// import { useState } from "react";
|
// import { useState } from "react";
|
||||||
|
|
||||||
const tenseOptions: { label: string | JSX.Element, value: VerbTense }[] = [{
|
const tenseOptions: { label: string | JSX.Element, value: VerbTense }[] = [{
|
||||||
|
@ -73,7 +73,7 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs }: {
|
||||||
verbs: VerbEntry[],
|
verbs: VerbEntry[],
|
||||||
verb: VerbSelection | undefined,
|
verb: VerbSelection | undefined,
|
||||||
subject: NPSelection | undefined,
|
subject: NPSelection | undefined,
|
||||||
onChange: (p: VerbSelection) => void,
|
onChange: (p: VerbSelection | undefined) => void,
|
||||||
changeSubject: (p: NPSelection | undefined) => void,
|
changeSubject: (p: NPSelection | undefined) => void,
|
||||||
}) {
|
}) {
|
||||||
// const [filters, useFilters] = useState<Filters>({
|
// const [filters, useFilters] = useState<Filters>({
|
||||||
|
@ -83,12 +83,10 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs }: {
|
||||||
// intransitive: true,
|
// intransitive: true,
|
||||||
// grammaticallyTransitive: true,
|
// grammaticallyTransitive: true,
|
||||||
// });
|
// });
|
||||||
const options = verbs.sort((a, b) => (a.entry.p.localeCompare(b.entry.p, "af-PS"))).map(makeVerbSelectOption);
|
function onVerbSelect(v: VerbEntry | undefined) {
|
||||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
// TODO: what to do when clearing
|
||||||
const v = verbs.find(v => v.entry.ts.toString() === value);
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
console.error("entry not found");
|
return onChange(v);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
onChange(makeVerbSelection(v, changeSubject, verb));
|
onChange(makeVerbSelection(v, changeSubject, verb));
|
||||||
}
|
}
|
||||||
|
@ -178,7 +176,13 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs }: {
|
||||||
const tOptions = (verb?.tenseCategory === "perfect") ? perfectTenseOptions : tenseOptions;
|
const tOptions = (verb?.tenseCategory === "perfect") ? perfectTenseOptions : tenseOptions;
|
||||||
return <div style={{ maxWidth: "225px", minWidth: "175px" }}>
|
return <div style={{ maxWidth: "225px", minWidth: "175px" }}>
|
||||||
<div>Verb:</div>
|
<div>Verb:</div>
|
||||||
<Select
|
<EntrySelect
|
||||||
|
entries={verbs}
|
||||||
|
value={verb?.verb}
|
||||||
|
onChange={onVerbSelect}
|
||||||
|
name="Verb"
|
||||||
|
/>
|
||||||
|
{/* <Select
|
||||||
value={verb && verb.verb.entry.ts.toString()}
|
value={verb && verb.verb.entry.ts.toString()}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
onChange={onEntrySelect}
|
onChange={onEntrySelect}
|
||||||
|
@ -189,7 +193,7 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs }: {
|
||||||
// // @ts-ignore
|
// // @ts-ignore
|
||||||
placeholder={verb ? options.find(o => o.value === (verb.verb.entry).ts.toString())?.label : "Select Verb..."}
|
placeholder={verb ? options.find(o => o.value === (verb.verb.entry).ts.toString())?.label : "Select Verb..."}
|
||||||
{...zIndexProps}
|
{...zIndexProps}
|
||||||
/>
|
/> */}
|
||||||
{verb && verb.changeTransitivity && <div className="text-center mt-3">
|
{verb && verb.changeTransitivity && <div className="text-center mt-3">
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import Select from "react-select";
|
|
||||||
import {
|
import {
|
||||||
makeSelectOption,
|
|
||||||
zIndexProps,
|
|
||||||
makeNounSelection,
|
makeNounSelection,
|
||||||
} from "./picker-tools";
|
} from "./picker-tools";
|
||||||
import {
|
import {
|
||||||
|
@ -11,6 +8,7 @@ import {
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
||||||
|
import EntrySelect from "../EntrySelect";
|
||||||
|
|
||||||
const filterOptions = [
|
const filterOptions = [
|
||||||
{
|
{
|
||||||
|
@ -59,18 +57,15 @@ function nounFilter(p: FilterPattern | undefined) {
|
||||||
: () => true;
|
: () => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function NPNounPicker({ onChange, noun, nouns, clearButton }: { nouns: NounEntry[], noun: NounSelection | undefined, onChange: (p: NounSelection) => void, clearButton?: JSX.Element }) {
|
function NPNounPicker({ onChange, noun, nouns, clearButton }: { nouns: NounEntry[], noun: NounSelection | undefined, onChange: (p: NounSelection | undefined) => void, clearButton?: JSX.Element }) {
|
||||||
const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||||
const [showFilter, setShowFilter] = useState<boolean>(false)
|
const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||||
const options = nouns
|
const nounsFiltered = nouns
|
||||||
.filter(nounFilter(patternFilter))
|
.filter(nounFilter(patternFilter))
|
||||||
.sort((a, b) => (a.p.localeCompare(b.p, "af-PS")))
|
.sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
|
||||||
.map(makeSelectOption);
|
function onEntrySelect(entry: NounEntry | undefined) {
|
||||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
|
||||||
const entry = nouns.find(n => n.ts.toString() === value);
|
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
console.error("entry not found");
|
return onChange(undefined);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
onChange(makeNounSelection(entry));
|
onChange(makeNounSelection(entry));
|
||||||
}
|
}
|
||||||
|
@ -101,17 +96,11 @@ function NPNounPicker({ onChange, noun, nouns, clearButton }: { nouns: NounEntry
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
{!(noun && noun.dynamicComplement) ? <div>
|
{!(noun && noun.dynamicComplement) ? <div>
|
||||||
<Select
|
<EntrySelect
|
||||||
value={noun && noun.entry.ts.toString()}
|
value={noun?.entry}
|
||||||
// @ts-ignore
|
entries={nounsFiltered}
|
||||||
onChange={onEntrySelect}
|
onChange={onEntrySelect}
|
||||||
className="mb-2"
|
name="Noun"
|
||||||
// @ts-ignore
|
|
||||||
options={options}
|
|
||||||
isSearchable
|
|
||||||
// @ts-ignore
|
|
||||||
placeholder={noun ? options.find(o => o.value === (noun.entry).ts.toString())?.label : "Select Noun..."}
|
|
||||||
{...zIndexProps}
|
|
||||||
/>
|
/>
|
||||||
</div> : <div>
|
</div> : <div>
|
||||||
{noun && <div>
|
{noun && <div>
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import Select from "react-select";
|
import EntrySelect from "../EntrySelect";
|
||||||
import {
|
|
||||||
makeSelectOption,
|
|
||||||
zIndexProps,
|
|
||||||
} from "./picker-tools";
|
|
||||||
|
|
||||||
function makeParticipleSelection(verb: VerbEntry): ParticipleSelection {
|
function makeParticipleSelection(verb: VerbEntry): ParticipleSelection {
|
||||||
return {
|
return {
|
||||||
|
@ -14,31 +10,23 @@ function makeParticipleSelection(verb: VerbEntry): ParticipleSelection {
|
||||||
function NPParticiplePicker({ onChange, participle, verbs, clearButton }: {
|
function NPParticiplePicker({ onChange, participle, verbs, clearButton }: {
|
||||||
verbs: VerbEntry[],
|
verbs: VerbEntry[],
|
||||||
participle: ParticipleSelection | undefined,
|
participle: ParticipleSelection | undefined,
|
||||||
onChange: (p: ParticipleSelection) => void,
|
onChange: (p: ParticipleSelection | undefined) => void,
|
||||||
clearButton: JSX.Element,
|
clearButton: JSX.Element,
|
||||||
}) {
|
}) {
|
||||||
const options = verbs.map(makeSelectOption)
|
function onEntrySelect(entry: VerbEntry | undefined) {
|
||||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
if (!entry) {
|
||||||
const verb = verbs.find(v => v.entry.ts.toString() === value);
|
onChange(undefined);
|
||||||
if (!verb) {
|
|
||||||
console.error("entry not found");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onChange(makeParticipleSelection(verb));
|
onChange(makeParticipleSelection(entry));
|
||||||
}
|
}
|
||||||
return <div style={{ maxWidth: "225px" }}>
|
return <div style={{ maxWidth: "225px" }}>
|
||||||
{clearButton}
|
{clearButton}
|
||||||
<Select
|
<EntrySelect
|
||||||
value={participle && participle.verb.entry.ts.toString()}
|
value={participle?.verb}
|
||||||
// @ts-ignore
|
entries={verbs}
|
||||||
onChange={onEntrySelect}
|
onChange={onEntrySelect}
|
||||||
className="mb-2"
|
name="Pariticple"
|
||||||
// @ts-ignore
|
|
||||||
options={options}
|
|
||||||
isSearchable
|
|
||||||
// // @ts-ignore
|
|
||||||
placeholder={participle ? options.find(o => o.value === (participle.verb.entry).ts.toString())?.label : "Select Participle..."}
|
|
||||||
{...zIndexProps}
|
|
||||||
/>
|
/>
|
||||||
{participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
{participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||||
<div>Masc.</div>
|
<div>Masc.</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ export function makeVerbSelectOption(e: VerbEntry): { value: string, label: stri
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeSelectOption(e: VerbEntry | NounEntry | AdjectiveEntry | LocativeAdverbEntry): { value: string, label: string } {
|
export function makeSelectOption(e: T.DictionaryEntry | VerbEntry | NounEntry | AdjectiveEntry | LocativeAdverbEntry): { value: string, label: string } {
|
||||||
const entry = "entry" in e ? e.entry : e;
|
const entry = "entry" in e ? e.entry : e;
|
||||||
const eng = (isVerbEntry(e))
|
const eng = (isVerbEntry(e))
|
||||||
? (getEnglishParticiple(e.entry))
|
? (getEnglishParticiple(e.entry))
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function isNounOrAdjEntry(e: Entry): e is (NounEntry | AdjectiveEntry) {
|
||||||
return isNounEntry(e) || isAdjectiveEntry(e);
|
return isNounEntry(e) || isAdjectiveEntry(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isVerbEntry(e: Entry): e is VerbEntry {
|
export function isVerbEntry(e: Entry | T.DictionaryEntry): e is VerbEntry {
|
||||||
return "entry" in e && !!e.entry.c?.startsWith("v.");
|
return "entry" in e && !!e.entry.c?.startsWith("v.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue