create EP picker
This commit is contained in:
parent
8d33931aa8
commit
e39f77c8b3
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@lingdocs/pashto-inflector",
|
"name": "@lingdocs/pashto-inflector",
|
||||||
"version": "2.8.7",
|
"version": "2.8.8",
|
||||||
"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",
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import useStickyState, { useStickyReducer } from "../../lib/useStickyState";
|
import useStickyState, { useStickyReducer } from "../../lib/useStickyState";
|
||||||
import NPPicker from "../np-picker/NPPicker";
|
|
||||||
import EquativePicker from "./EquativePicker";
|
|
||||||
import EPDisplay from "./EPDisplay";
|
import EPDisplay from "./EPDisplay";
|
||||||
import ButtonSelect from "../ButtonSelect";
|
import ButtonSelect from "../ButtonSelect";
|
||||||
import EqCompPicker from "./eq-comp-picker/EqCompPicker";
|
|
||||||
import EqChartsDisplay from "./EqChartsDisplay";
|
import EqChartsDisplay from "./EqChartsDisplay";
|
||||||
import epsReducer from "./eps-reducer";
|
import epsReducer from "./eps-reducer";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { completeEPSelection } from "../../lib/phrase-building/render-ep";
|
import { completeEPSelection } from "../../lib/phrase-building/render-ep";
|
||||||
import { makeEPSBlocks } from "../../lib/phrase-building/blocks-utils";
|
import { makeEPSBlocks } from "../../lib/phrase-building/blocks-utils";
|
||||||
import APPicker from "../ap-picker/APPicker";
|
import EquativePicker from "./EquativePicker";
|
||||||
import autoAnimate from "@formkit/auto-animate";
|
import autoAnimate from "@formkit/auto-animate";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import LZString from "lz-string";
|
import LZString from "lz-string";
|
||||||
|
import EPPicker from "./EPPicker";
|
||||||
const phraseURLParam = "EPhrase";
|
const phraseURLParam = "EPhrase";
|
||||||
|
|
||||||
const blankEps: T.EPSelectionState = {
|
const blankEps: T.EPSelectionState = {
|
||||||
|
@ -35,14 +33,11 @@ const blankEps: T.EPSelectionState = {
|
||||||
function EPExplorer(props: {
|
function EPExplorer(props: {
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
entryFeeder: T.EntryFeeder,
|
entryFeeder: T.EntryFeeder,
|
||||||
} & ({
|
}) {
|
||||||
eps: T.EPSelectionState,
|
|
||||||
onChange: (eps: T.EPSelectionState) => void,
|
|
||||||
} | {})) {
|
|
||||||
const [mode, setMode] = useStickyState<"charts" | "phrases">("charts", "EPExplorerMode");
|
const [mode, setMode] = useStickyState<"charts" | "phrases">("charts", "EPExplorerMode");
|
||||||
const [eps, adjustEps] = useStickyReducer(
|
const [eps, adjustEps] = useStickyReducer(
|
||||||
epsReducer,
|
epsReducer,
|
||||||
"eps" in props ? props.eps : blankEps,
|
blankEps,
|
||||||
"EPState7",
|
"EPState7",
|
||||||
flashMessage,
|
flashMessage,
|
||||||
);
|
);
|
||||||
|
@ -63,6 +58,9 @@ function EPExplorer(props: {
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
function handleEpsChange(e: T.EPSelectionState) {
|
||||||
|
adjustEps({ type: "load EPS", payload: e });
|
||||||
|
}
|
||||||
function flashMessage(msg: string) {
|
function flashMessage(msg: string) {
|
||||||
setAlert(msg);
|
setAlert(msg);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -114,86 +112,21 @@ function EPExplorer(props: {
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
{mode === "phrases" && <div className="clickable h5" onClick={() => adjustEps({ type: "insert new AP" })}>+ AP</div>}
|
{mode === "phrases" &&
|
||||||
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
|
<EPPicker
|
||||||
{mode === "phrases" && <>
|
|
||||||
{eps.blocks.map(({ block, key }, i) => (
|
|
||||||
<div className="my-2 card block-card p-1 mx-1" key={key}>
|
|
||||||
<div className="d-flex flex-row justify-content-between mb-1" style={{ height: "1rem" }}>
|
|
||||||
{i > 0 ? <div
|
|
||||||
className="small clickable ml-1"
|
|
||||||
onClick={() => adjustEps({ type: "shift block", payload: { index: i, direction: "back" }})}
|
|
||||||
>
|
|
||||||
<i className="fas fa-chevron-left" />
|
|
||||||
</div> : <div/>}
|
|
||||||
{i < eps.blocks.length - 1 ? <div
|
|
||||||
className="small clickable mr-1"
|
|
||||||
onClick={() => adjustEps({ type: "shift block", payload: { index: i, direction: "forward" }})}
|
|
||||||
>
|
|
||||||
<i className="fas fa-chevron-right" />
|
|
||||||
</div> : <div/>}
|
|
||||||
</div>
|
|
||||||
{block && block.type === "subjectSelection"
|
|
||||||
? <NPPicker
|
|
||||||
phraseIsComplete={phraseIsComplete}
|
|
||||||
heading={<div className="h5 text-center">Subject</div>}
|
|
||||||
entryFeeder={props.entryFeeder}
|
|
||||||
np={block.selection}
|
|
||||||
counterPart={undefined}
|
|
||||||
role="subject"
|
|
||||||
onChange={payload => adjustEps({ type: "set subject", payload })}
|
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
/>
|
|
||||||
: <APPicker
|
|
||||||
phraseIsComplete={phraseIsComplete}
|
|
||||||
heading="AP"
|
|
||||||
entryFeeder={props.entryFeeder}
|
entryFeeder={props.entryFeeder}
|
||||||
AP={block}
|
eps={eps}
|
||||||
opts={props.opts}
|
onChange={handleEpsChange}
|
||||||
onChange={AP => adjustEps({ type: "set AP", payload: { index: i, AP } })}
|
|
||||||
onRemove={() => adjustEps({ type: "remove AP", payload: i })}
|
|
||||||
/>}
|
/>}
|
||||||
</div>
|
{mode === "charts" && <div className="my-2">
|
||||||
))}
|
|
||||||
<div className="my-2 card block-card p-1">
|
|
||||||
<div className="h5 text-center">Predicate</div>
|
|
||||||
<div className="mb-2 text-center">
|
|
||||||
<ButtonSelect
|
|
||||||
small
|
|
||||||
options={[
|
|
||||||
{ value: "NP", label: "NP" },
|
|
||||||
{ value: "Complement", label: "Complement" },
|
|
||||||
]}
|
|
||||||
value={eps.predicate.type}
|
|
||||||
handleChange={payload => adjustEps({ type: "set predicate type", payload })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{eps.predicate.type === "NP" ? <NPPicker
|
|
||||||
phraseIsComplete={phraseIsComplete}
|
|
||||||
entryFeeder={props.entryFeeder}
|
|
||||||
np={eps.predicate.type === "NP" ? eps.predicate.NP : undefined}
|
|
||||||
counterPart={undefined}
|
|
||||||
role="subject"
|
|
||||||
onChange={payload => adjustEps({ type: "set predicate NP", payload })}
|
|
||||||
opts={props.opts}
|
|
||||||
/> : <EqCompPicker
|
|
||||||
phraseIsComplete={phraseIsComplete}
|
|
||||||
comp={eps.predicate.type === "Complement" ? eps.predicate.Complement : undefined}
|
|
||||||
onChange={payload => adjustEps({ type: "set predicate comp", payload })}
|
|
||||||
opts={props.opts}
|
|
||||||
entryFeeder={props.entryFeeder}
|
|
||||||
/>}
|
|
||||||
</div>
|
|
||||||
</>}
|
|
||||||
<div className="my-2">
|
|
||||||
<div className="h5 text-center clickable">Equative</div>
|
<div className="h5 text-center clickable">Equative</div>
|
||||||
<EquativePicker
|
<EquativePicker
|
||||||
equative={eps.equative}
|
equative={eps.equative}
|
||||||
onChange={payload => adjustEps({ type: "set equative", payload })}
|
onChange={payload => adjustEps({ type: "set equative", payload })}
|
||||||
hideNegative={mode === "charts"}
|
hideNegative={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>}
|
||||||
</div>
|
|
||||||
{mode === "charts" && <EqChartsDisplay tense={eps.equative.tense} opts={props.opts} />}
|
{mode === "charts" && <EqChartsDisplay tense={eps.equative.tense} opts={props.opts} />}
|
||||||
{mode === "phrases" && <EPDisplay
|
{mode === "phrases" && <EPDisplay
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
import * as T from "../../types";
|
||||||
|
import NPPicker from "../np-picker/NPPicker";
|
||||||
|
import EquativePicker from "./EquativePicker";
|
||||||
|
import ButtonSelect from "../ButtonSelect";
|
||||||
|
import EqCompPicker from "./eq-comp-picker/EqCompPicker";
|
||||||
|
import epsReducer, { EpsReducerAction } from "./eps-reducer";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { completeEPSelection } from "../../lib/phrase-building/render-ep";
|
||||||
|
import APPicker from "../ap-picker/APPicker";
|
||||||
|
import autoAnimate from "@formkit/auto-animate";
|
||||||
|
|
||||||
|
function EPPicker({ opts, eps, onChange, entryFeeder }: {
|
||||||
|
opts: T.TextOptions,
|
||||||
|
eps: T.EPSelectionState,
|
||||||
|
onChange: (eps: T.EPSelectionState) => void,
|
||||||
|
entryFeeder: T.EntryFeeder,
|
||||||
|
}) {
|
||||||
|
const parent = useRef<HTMLDivElement>(null);
|
||||||
|
const [alert, setAlert] = useState<string | undefined>("");
|
||||||
|
useEffect(() => {
|
||||||
|
parent.current && autoAnimate(parent.current);
|
||||||
|
}, [parent]);
|
||||||
|
function adjustEps(action: EpsReducerAction) {
|
||||||
|
onChange(epsReducer(eps, action, handleAlert));
|
||||||
|
}
|
||||||
|
function handleAlert(msg: string) {
|
||||||
|
setAlert(msg);
|
||||||
|
setTimeout(() => {
|
||||||
|
setAlert(undefined);
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
const phraseIsComplete = !!completeEPSelection(eps);
|
||||||
|
return <div>
|
||||||
|
<div className="clickable h5" onClick={() => adjustEps({ type: "insert new AP" })}>+ AP</div>
|
||||||
|
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
|
||||||
|
{eps.blocks.map(({ block, key }, i) => (
|
||||||
|
<div className="my-2 card block-card p-1 mx-1" key={key}>
|
||||||
|
<div className="d-flex flex-row justify-content-between mb-1" style={{ height: "1rem" }}>
|
||||||
|
{i > 0 ? <div
|
||||||
|
className="small clickable ml-1"
|
||||||
|
onClick={() => adjustEps({ type: "shift block", payload: { index: i, direction: "back" }})}
|
||||||
|
>
|
||||||
|
<i className="fas fa-chevron-left" />
|
||||||
|
</div> : <div/>}
|
||||||
|
{i < eps.blocks.length - 1 ? <div
|
||||||
|
className="small clickable mr-1"
|
||||||
|
onClick={() => adjustEps({ type: "shift block", payload: { index: i, direction: "forward" }})}
|
||||||
|
>
|
||||||
|
<i className="fas fa-chevron-right" />
|
||||||
|
</div> : <div/>}
|
||||||
|
</div>
|
||||||
|
{block && block.type === "subjectSelection"
|
||||||
|
? <NPPicker
|
||||||
|
phraseIsComplete={phraseIsComplete}
|
||||||
|
heading={<div className="h5 text-center">Subject</div>}
|
||||||
|
entryFeeder={entryFeeder}
|
||||||
|
np={block.selection}
|
||||||
|
counterPart={undefined}
|
||||||
|
role="subject"
|
||||||
|
onChange={payload => adjustEps({ type: "set subject", payload })}
|
||||||
|
opts={opts}
|
||||||
|
/>
|
||||||
|
: <APPicker
|
||||||
|
phraseIsComplete={phraseIsComplete}
|
||||||
|
heading="AP"
|
||||||
|
entryFeeder={entryFeeder}
|
||||||
|
AP={block}
|
||||||
|
opts={opts}
|
||||||
|
onChange={AP => adjustEps({ type: "set AP", payload: { index: i, AP } })}
|
||||||
|
onRemove={() => adjustEps({ type: "remove AP", payload: i })}
|
||||||
|
/>}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="my-2 card block-card p-1">
|
||||||
|
<div className="h5 text-center">Predicate</div>
|
||||||
|
<div className="mb-2 text-center">
|
||||||
|
<ButtonSelect
|
||||||
|
small
|
||||||
|
options={[
|
||||||
|
{ value: "NP", label: "NP" },
|
||||||
|
{ value: "Complement", label: "Complement" },
|
||||||
|
]}
|
||||||
|
value={eps.predicate.type}
|
||||||
|
handleChange={payload => adjustEps({ type: "set predicate type", payload })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{eps.predicate.type === "NP" ? <NPPicker
|
||||||
|
phraseIsComplete={phraseIsComplete}
|
||||||
|
entryFeeder={entryFeeder}
|
||||||
|
np={eps.predicate.type === "NP" ? eps.predicate.NP : undefined}
|
||||||
|
counterPart={undefined}
|
||||||
|
role="subject"
|
||||||
|
onChange={payload => adjustEps({ type: "set predicate NP", payload })}
|
||||||
|
opts={opts}
|
||||||
|
/> : <EqCompPicker
|
||||||
|
phraseIsComplete={phraseIsComplete}
|
||||||
|
comp={eps.predicate.type === "Complement" ? eps.predicate.Complement : undefined}
|
||||||
|
onChange={payload => adjustEps({ type: "set predicate comp", payload })}
|
||||||
|
opts={opts}
|
||||||
|
entryFeeder={entryFeeder}
|
||||||
|
/>}
|
||||||
|
</div>
|
||||||
|
<div className="my-2">
|
||||||
|
<div className="h5 text-center clickable">Equative</div>
|
||||||
|
<EquativePicker
|
||||||
|
equative={eps.equative}
|
||||||
|
onChange={payload => adjustEps({ type: "set equative", payload })}
|
||||||
|
hideNegative={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{alert && <div className="alert alert-warning text-center" role="alert" style={{
|
||||||
|
position: "fixed",
|
||||||
|
top: "30%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
zIndex: 9999999999999,
|
||||||
|
}}>
|
||||||
|
{alert}
|
||||||
|
</div>}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EPPicker;
|
|
@ -7,7 +7,7 @@ import { isUnisexNounEntry } from "../../lib/type-predicates";
|
||||||
import { checkEPForMiniPronounsError } from "../../lib/phrase-building/compile";
|
import { checkEPForMiniPronounsError } from "../../lib/phrase-building/compile";
|
||||||
import { adjustSubjectSelection, getSubjectSelection, insertNewAP, removeAP, setAP, shiftBlock } from "../../lib/phrase-building/blocks-utils";
|
import { adjustSubjectSelection, getSubjectSelection, insertNewAP, removeAP, setAP, shiftBlock } from "../../lib/phrase-building/blocks-utils";
|
||||||
|
|
||||||
type EpsReducerAction = {
|
export type EpsReducerAction = {
|
||||||
type: "set predicate type",
|
type: "set predicate type",
|
||||||
payload: "NP" | "Complement",
|
payload: "NP" | "Complement",
|
||||||
} | {
|
} | {
|
||||||
|
|
|
@ -149,6 +149,7 @@ import {
|
||||||
renderAPSelection,
|
renderAPSelection,
|
||||||
} from "./lib/phrase-building/render-ap";
|
} from "./lib/phrase-building/render-ap";
|
||||||
import NPPicker from "./components/np-picker/NPPicker";
|
import NPPicker from "./components/np-picker/NPPicker";
|
||||||
|
import EPPicker from "./components/ep-explorer/EPPicker";
|
||||||
import EPExplorer from "./components/ep-explorer/EPExplorer";
|
import EPExplorer from "./components/ep-explorer/EPExplorer";
|
||||||
import shuffleArray from "./lib/shuffle-array";
|
import shuffleArray from "./lib/shuffle-array";
|
||||||
import defaultTextOptions from "./lib/default-text-options";
|
import defaultTextOptions from "./lib/default-text-options";
|
||||||
|
@ -253,6 +254,7 @@ export {
|
||||||
APBlock,
|
APBlock,
|
||||||
Block,
|
Block,
|
||||||
EPDisplay,
|
EPDisplay,
|
||||||
|
EPPicker,
|
||||||
// OTHER
|
// OTHER
|
||||||
typePredicates,
|
typePredicates,
|
||||||
grammarUnits,
|
grammarUnits,
|
||||||
|
|
Loading…
Reference in New Issue