From 346a89df29538102f9112b9d6a44a5f0d7ee99a1 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 22 Jun 2022 18:52:09 -0500 Subject: [PATCH] up --- package.json | 2 +- src/components/vp-explorer/TensePicker.tsx | 2 +- src/components/vp-explorer/VPExplorer.tsx | 172 ++------------------ src/components/vp-explorer/VPPicker.tsx | 181 +++++++++++++++++++++ src/lib/phrase-building/blocks-utils.ts | 14 +- src/library.ts | 6 + 6 files changed, 217 insertions(+), 160 deletions(-) create mode 100644 src/components/vp-explorer/VPPicker.tsx diff --git a/package.json b/package.json index 7f6c4bb..759376c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "3.0.5", + "version": "3.0.6", "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/components/vp-explorer/TensePicker.tsx b/src/components/vp-explorer/TensePicker.tsx index 3ba10a8..940f81c 100644 --- a/src/components/vp-explorer/TensePicker.tsx +++ b/src/components/vp-explorer/TensePicker.tsx @@ -177,7 +177,7 @@ function TensePicker(props: ({ : verbTenseOptions; const showImperativeOption = ("vps" in props && props.vps.verb.voice === "active") || ("vpsComplete" in props && props.vpsComplete.verb.voice !== "active"); - const canHaveFormula = "vps" in props; + const canHaveFormula = "vps" in props && props.mode !== "quiz"; return
diff --git a/src/components/vp-explorer/VPExplorer.tsx b/src/components/vp-explorer/VPExplorer.tsx index 2200698..def522e 100644 --- a/src/components/vp-explorer/VPExplorer.tsx +++ b/src/components/vp-explorer/VPExplorer.tsx @@ -1,4 +1,3 @@ -import NPPicker, { shrunkenBackground } from "../np-picker/NPPicker"; import VerbPicker from "./VerbPicker"; import TensePicker from "./TensePicker"; import VPDisplay from "./VPDisplay"; @@ -7,17 +6,14 @@ import * as T from "../../types"; import ChartDisplay from "./VPChartDisplay"; import useStickyState, { useStickyReducer } from "../../lib/useStickyState"; import { makeVPSelectionState } from "./verb-selection"; -import { useEffect, useRef, useState } from "react"; -import { getKingAndServant, renderVP } from "../../lib/phrase-building/render-vp"; -import { completeVPSelection, isPastTense } from "../../lib/phrase-building/vp-tools"; +import { useEffect, useState } from "react"; +import { completeVPSelection } from "../../lib/phrase-building/vp-tools"; import VPExplorerQuiz from "./VPExplorerQuiz"; -import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal"; // @ts-ignore import LZString from "lz-string"; import { vpsReducer } from "./vps-reducer"; -import APPicker from "../ap-picker/APPicker"; -import autoAnimate from "@formkit/auto-animate"; -import { getObjectSelection, getSubjectSelection, isNoObject } from "../../lib/phrase-building/blocks-utils"; +import { getObjectSelection } from "../../lib/phrase-building/blocks-utils"; +import VPPicker from "./VPPicker"; const phraseURLParam = "VPhrase"; @@ -56,16 +52,6 @@ function VPExplorer(props: { ); const [showClipped, setShowClipped] = useState(""); const [alert, setAlert] = useState(undefined); - const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false); - const parent = useRef(null); - useEffect(() => { - parent.current && autoAnimate(parent.current); - }, [parent]); - const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense); - const roles = getKingAndServant( - isPast, - vps.verb.transitivity !== "intransitive", - ); function flashMessage(msg: string) { setAlert(msg); setTimeout(() => { @@ -90,18 +76,6 @@ function VPExplorer(props: { } // eslint-disable-next-line }, []); - function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) { - adjustVps({ - type: "set subject", - payload: { subject, skipPronounConflictCheck }, - }); - } - function handleObjectChange(object: T.NPSelection | undefined) { - adjustVps({ - type: "set object", - payload: object, - }); - } function handleSubjObjSwap() { adjustVps({ type: "swap subj/obj" }); } @@ -138,16 +112,8 @@ function VPExplorer(props: { flashClippedMessage("Copied phrase code to clipboard"); } const object = getObjectSelection(vps.blocks).selection; - const subject = getSubjectSelection(vps.blocks).selection; const VPS = completeVPSelection(vps); const phraseIsComplete = !!VPS; - const rendered = VPS ? renderVP(VPS) : undefined; - const servantIsShrunk = includesShrunkenServant(rendered?.kids); - function toggleServantShrink() { - adjustVps({ - type: "toggle servant shrink", - }); - } return
subj/obj
} - {mode === "phrases" &&
adjustVps({ type: "insert new AP" })}>+ AP
} - {mode !== "quiz" &&
- {mode === "phrases" && <> - {vps.blocks.map(({ block, key }, i, blocks) => { - if (isNoObject(block)) return null; - return
-
- {(i > 0 && !isNoObject(blocks[i - 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})} - > - -
:
} - {(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})} - > - -
:
} -
- {(!block || block.type === "AP") - ? adjustVps({ type: "set AP", payload: { index: i, AP } })} - onRemove={() => adjustVps({ type: "remove AP", payload: i })} - /> - : (block?.type === "subjectSelection") - ? setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}
- :
- Subject - {` `} - setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant} - {` `} - {(rendered && rendered.whatsAdjustable !== "king") && - - {!servantIsShrunk ? "🪄" : "👶"} - - } -
} - entryFeeder={props.entryFeeder} - np={block.selection} - counterPart={vps.verb ? object : undefined} - role={(isPast && vps.verb.transitivity !== "intransitive") - ? "ergative" - : "subject" - } - onChange={handleSubjectChange} - opts={props.opts} - isShrunk={(servantIsShrunk && roles.servant === "subject")} - /> - : (vps.verb && block?.type === "objectSelection" && block.selection !== "none") - ?
- {(typeof block.selection === "number") - ?
- {roles.king === "object" - ?
setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
- :
Object
} -
Unspoken 3rd Pers. Masc. Plur.
-
- : setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
- :
- Object - {` `} - setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant} - {` `} - {(rendered && rendered.whatsAdjustable !== "king") && - - {!servantIsShrunk ? "🪄" : "👶"} - - } -
} - entryFeeder={props.entryFeeder} - role="object" - np={block.selection} - counterPart={subject} - onChange={handleObjectChange} - opts={props.opts} - isShrunk={(servantIsShrunk && roles.servant === "object")} - />} -
- : null} -
; - })} - } -
- -
+ {mode === "phrases" && adjustVps({ type: "load vps", payload: vps })} + vps={vps} + />} + {mode !== "phrases" &&
+
} {mode === "phrases" && } {mode === "charts" && } {mode === "quiz" && } - {showClipped &&
( - k.type === "mini-pronoun" && k.source === "servant" - )); -} - diff --git a/src/components/vp-explorer/VPPicker.tsx b/src/components/vp-explorer/VPPicker.tsx new file mode 100644 index 0000000..7ab1005 --- /dev/null +++ b/src/components/vp-explorer/VPPicker.tsx @@ -0,0 +1,181 @@ +import NPPicker, { shrunkenBackground } from "../np-picker/NPPicker"; +import TensePicker from "./TensePicker"; +import * as T from "../../types"; +import { useEffect, useRef, useState } from "react"; +import { getKingAndServant, renderVP } from "../../lib/phrase-building/render-vp"; +import { completeVPSelection, isPastTense } from "../../lib/phrase-building/vp-tools"; +import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal"; +import { vpsReducer, VpsReducerAction } from "./vps-reducer"; +import APPicker from "../ap-picker/APPicker"; +import autoAnimate from "@formkit/auto-animate"; +import { getObjectSelection, getSubjectSelection, includesShrunkenServant, isNoObject } from "../../lib/phrase-building/blocks-utils"; + +function VPPicker({ opts, vps, onChange, entryFeeder }: { + opts: T.TextOptions, + vps: T.VPSelectionState, + onChange: (eps: T.VPSelectionState) => void, + entryFeeder: T.EntryFeeder, +}) { + const parent = useRef(null); + useEffect(() => { + parent.current && autoAnimate(parent.current); + }, [parent]); + const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false); + const [alert, setAlert] = useState(undefined); + function flashMessage(msg: string) { + setAlert(msg); + setTimeout(() => { + setAlert(undefined); + }, 1500); + } + function adjustVps(action: VpsReducerAction) { + const newVps = vpsReducer(vps, action, flashMessage); + onChange(newVps); + } + function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) { + adjustVps({ + type: "set subject", + payload: { subject, skipPronounConflictCheck }, + }); + } + function handleObjectChange(object: T.NPSelection | undefined) { + adjustVps({ + type: "set object", + payload: object, + }); + } + const object = getObjectSelection(vps.blocks).selection; + const subject = getSubjectSelection(vps.blocks).selection; + const VPS = completeVPSelection(vps); + const phraseIsComplete = !!VPS; + const rendered = VPS ? renderVP(VPS) : undefined; + const servantIsShrunk = includesShrunkenServant(rendered?.kids); + const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense); + const roles = getKingAndServant( + isPast, + vps.verb.transitivity !== "intransitive", + ); + return
+
adjustVps({ type: "insert new AP" })}>+ AP
+
+ {vps.blocks.map(({ block, key }, i, blocks) => { + if (isNoObject(block)) return null; + return
+
+ {(i > 0 && !isNoObject(blocks[i - 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})} + > + +
:
} + {(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})} + > + +
:
} +
+ {(!block || block.type === "AP") + ? adjustVps({ type: "set AP", payload: { index: i, AP } })} + onRemove={() => adjustVps({ type: "remove AP", payload: i })} + /> + : (block?.type === "subjectSelection") + ? setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}
+ :
+ Subject + {` `} + setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant} + {` `} + {(rendered && rendered.whatsAdjustable !== "king") && + adjustVps({ type: "toggle servant shrink" })} className="mx-2 clickable"> + {!servantIsShrunk ? "🪄" : "👶"} + + } +
} + entryFeeder={entryFeeder} + np={block.selection} + counterPart={vps.verb ? object : undefined} + role={(isPast && vps.verb.transitivity !== "intransitive") + ? "ergative" + : "subject" + } + onChange={handleSubjectChange} + opts={opts} + isShrunk={(servantIsShrunk && roles.servant === "subject")} + /> + : (vps.verb && block?.type === "objectSelection" && block.selection !== "none") + ?
+ {(typeof block.selection === "number") + ?
+ {roles.king === "object" + ?
setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
+ :
Object
} +
Unspoken 3rd Pers. Masc. Plur.
+
+ : setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
+ :
+ Object + {` `} + setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant} + {` `} + {(rendered && rendered.whatsAdjustable !== "king") && + adjustVps({ type: "toggle servant shrink" })} className="mx-2 clickable"> + {!servantIsShrunk ? "🪄" : "👶"} + + } +
} + entryFeeder={entryFeeder} + role="object" + np={block.selection} + counterPart={subject} + onChange={handleObjectChange} + opts={opts} + isShrunk={(servantIsShrunk && roles.servant === "object")} + />} +
+ : null} +
; + })} +
+ +
+
+ + {alert &&
+ {alert} +
} +
; +} + +export default VPPicker; \ No newline at end of file diff --git a/src/lib/phrase-building/blocks-utils.ts b/src/lib/phrase-building/blocks-utils.ts index 7e183a9..ae8d60a 100644 --- a/src/lib/phrase-building/blocks-utils.ts +++ b/src/lib/phrase-building/blocks-utils.ts @@ -44,11 +44,14 @@ export function getVerbFromBlocks(blocks: T.Block[][]): T.VerbRenderedBlock { return v; } -export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRenderedBlock, perfectiveHead: T.PerfectiveHeadBlock } { +export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRenderedBlock, perfectiveHead: T.PerfectiveHeadBlock | undefined } { const verb = getVerbFromBlocks(blocks); const perfectiveHead = blocks[0].find(f => f.type === "perfectiveHead"); if (!perfectiveHead || perfectiveHead.type !== "perfectiveHead") { - throw new Error("perfectiveHead not found in blocks"); + return { + verb, + perfectiveHead: undefined, + }; } return { verb, @@ -56,6 +59,13 @@ export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRen }; } +export function includesShrunkenServant(kids?: T.Kid[]): boolean { + if (!kids) return false; + return kids.some(k => ( + k.type === "mini-pronoun" && k.source === "servant" + )); +} + export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered { const b = blocks[0].find(f => f.type === "predicateSelection"); if (!b || b.type !== "predicateSelection") { diff --git a/src/library.ts b/src/library.ts index 5ffdc34..c123403 100644 --- a/src/library.ts +++ b/src/library.ts @@ -30,6 +30,7 @@ import VerbInfo, { RootsAndStems } from "./components/verb-info/VerbInfo"; import VPExplorer from "./components/vp-explorer/VPExplorer"; import useStickyState from "./lib/useStickyState"; import Block, { NPBlock, APBlock } from "./components/blocks/Block"; +import { roleIcon } from "./components/vp-explorer/VPExplorerExplanationModal"; import { makePsString, removeFVarients, @@ -158,6 +159,8 @@ import genderColors from "./lib/gender-colors"; import * as Types from "./types"; import * as typePredicates from "./lib/type-predicates"; import APPicker from "./components/ap-picker/APPicker"; +import VPDisplay from "./components/vp-explorer/VPDisplay"; +import VPPicker from "./components/vp-explorer/VPPicker"; export { // FUNCTIONS @@ -228,6 +231,7 @@ export { getPashtoFromRendered, renderAPSelection, getEnglishVerb, + roleIcon, // protobuf helpers readDictionary, writeDictionary, @@ -254,7 +258,9 @@ export { APBlock, Block, EPDisplay, + VPDisplay, EPPicker, + VPPicker, // OTHER typePredicates, grammarUnits,