fix up the new prompt UI

This commit is contained in:
Olivier Gagnon 2022-03-17 16:44:44 -04:00
parent 88df76a868
commit 3cdf0452a4
2 changed files with 79 additions and 99 deletions

@ -5999,7 +5999,10 @@ export interface NS extends Singularity {
* @param options - Options to modify the prompt the player is shown. * @param options - Options to modify the prompt the player is shown.
* @returns True if the player click Yes; false if the player clicks No; or the value entered by the player. * @returns True if the player click Yes; false if the player clicks No; or the value entered by the player.
*/ */
prompt(txt: string, options?: { type?: "boolean"|"text"|"select"|undefined; choices?: string[] | { [key: string]: string | number } }): Promise<boolean | string>; prompt(
txt: string,
options?: { type?: "boolean" | "text" | "select" | undefined; choices?: string[] },
): Promise<boolean | string>;
/** /**
* Open up a message box. * Open up a message box.

@ -1,136 +1,113 @@
import React, { useState, useEffect, Dispatch, SetStateAction } from "react"; import React, { useState, useEffect } from "react";
import { EventEmitter } from "../../utils/EventEmitter"; import { EventEmitter } from "../../utils/EventEmitter";
import { Modal } from "./Modal"; import { Modal } from "./Modal";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Select, { SelectChangeEvent } from "@mui/material/Select"; import Select, { SelectChangeEvent } from "@mui/material/Select";
import TextField from '@mui/material/TextField'; import TextField from "@mui/material/TextField";
import { KEY } from '../../utils/helpers/keyCodes'; import MenuItem from "@mui/material/MenuItem";
import MenuItem from '@mui/material/MenuItem';
export const PromptEvent = new EventEmitter<[Prompt]>(); export const PromptEvent = new EventEmitter<[Prompt]>();
interface Prompt { interface Prompt {
txt: string; txt: string;
options?: { type?: string; choices?: string[] | { [key: string]: string | number } }; options?: { type?: string; choices?: string[] };
resolve: (result: boolean | string) => void; resolve: (result: boolean | string) => void;
} }
export function PromptManager(): React.ReactElement { export function PromptManager(): React.ReactElement {
const [prompt, setPrompt] = useState<Prompt | null>(null); const [prompt, setPrompt] = useState<Prompt | null>(null);
useEffect( useEffect(() => {
() => return PromptEvent.subscribe((p: Prompt) => {
PromptEvent.subscribe((p: Prompt) => {
setPrompt(p); setPrompt(p);
}), });
[], }, []);
);
const valueState = useState('') if (prompt === null) {
return <></>;
}
function close(): void { function close(): void {
if (prompt === null) return; if (prompt === null) return;
if (["text", "select"].includes(prompt?.options?.type ?? "")) {
prompt.resolve("");
} else {
prompt.resolve(false); prompt.resolve(false);
valueState[1]('') }
setPrompt(null); setPrompt(null);
} }
let promptRenderer; const types: { [key: string]: any } = {
switch (prompt?.options?.type) { text: PromptMenuText,
case 'text': { select: PromptMenuSelect,
promptRenderer = promptMenuText; };
break;
}
case 'select': { let PromptContent = PromptMenuBoolean;
promptRenderer = promptMenuSelect; if (prompt?.options?.type) PromptContent = types[prompt?.options?.type];
break;
}
default: { const resolve = (value: boolean | string): void => {
promptRenderer = promptMenuBoolean; prompt.resolve(value);
} setPrompt(null);
} };
return ( return (
<>
{prompt != null && (
<Modal open={true} onClose={close}> <Modal open={true} onClose={close}>
<Typography>{prompt.txt}</Typography> <Typography>{prompt.txt}</Typography>
{promptRenderer(prompt, setPrompt, valueState)} <PromptContent prompt={prompt} resolve={resolve} />
</Modal> </Modal>
)}
</>
); );
} }
function promptMenuBoolean(prompt: Prompt | null, setPrompt: Dispatch<SetStateAction<Prompt | null>>): React.ReactElement { interface IContentProps {
const yes = (): void => { prompt: Prompt;
if (prompt !== null) { resolve: (value: boolean | string) => void;
prompt.resolve(true);
setPrompt(null);
}
}
const no = (): void => {
if (prompt !== null) {
prompt.resolve(false);
setPrompt(null);
}
} }
function PromptMenuBoolean({ resolve }: IContentProps): React.ReactElement {
const yes = (): void => resolve(true);
const no = (): void => resolve(false);
return ( return (
<> <>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', paddingTop: '10px' }}> <div style={{ display: "flex", justifyContent: "center", alignItems: "center", paddingTop: "10px" }}>
<Button style={{ marginRight: 'auto' }} onClick={yes}>Yes</Button> <Button style={{ marginRight: "auto" }} onClick={yes}>
Yes
</Button>
<Button onClick={no}>No</Button> <Button onClick={no}>No</Button>
</div> </div>
</> </>
); );
} }
function promptMenuText(prompt: Prompt | null, setPrompt: Dispatch<SetStateAction<Prompt | null>>, valueState: [string, Dispatch<SetStateAction<string>>]): React.ReactElement { function PromptMenuText({ resolve }: IContentProps): React.ReactElement {
const [value, setValue] = valueState const [value, setValue] = useState("");
const submit = (): void => { const submit = (): void => resolve(value);
if (prompt !== null) {
prompt.resolve(value);
setValue('')
setPrompt(null);
}
}
const onInput = (event: React.ChangeEvent<HTMLInputElement>): void => { const onInput = (event: React.ChangeEvent<HTMLInputElement>): void => {
setValue(event.target.value); setValue(event.target.value);
} };
const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => { const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
event.stopPropagation(); event.stopPropagation();
if (prompt !== null && event.keyCode === KEY.ENTER) { if (event.key === "Enter") {
event.preventDefault(); event.preventDefault();
submit(); submit();
} }
} };
return ( return (
<> <>
<div style={{ display: 'flex', alignItems: 'center', paddingTop: '10px' }}> <div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
<TextField <TextField
autoFocus autoFocus
value={value} value={value}
onInput={onInput} onInput={onInput}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
style={{ flex: '1 0 auto' }} style={{ flex: "1 0 auto" }}
InputProps={{ InputProps={{
endAdornment: ( endAdornment: <Button onClick={submit}>Confirm</Button>,
<Button
onClick={() => {
submit();
}}
>
Confirm
</Button>
),
}} }}
/> />
</div> </div>
@ -138,37 +115,37 @@ function promptMenuText(prompt: Prompt | null, setPrompt: Dispatch<SetStateActio
); );
} }
function promptMenuSelect(prompt: Prompt | null, setPrompt: Dispatch<SetStateAction<Prompt | null>>, valueState: [string, Dispatch<SetStateAction<string>>]): React.ReactElement { function PromptMenuSelect({ prompt, resolve }: IContentProps): React.ReactElement {
const [value, setValue] = valueState const [value, setValue] = useState("");
const submit = (): void => { const submit = (): void => resolve(value);
if (prompt !== null) {
prompt.resolve(value);
setValue('');
setPrompt(null);
}
}
const onChange = (event: SelectChangeEvent<string>): void => { const onChange = (event: SelectChangeEvent<string>): void => {
setValue(event.target.value); setValue(event.target.value);
} };
const getItems = (choices: string[] | { [key: string]: string | number }) : React.ReactElement[] => { const getItems = (choices: string[]): React.ReactElement[] => {
const content = []; const content = [];
for (const i in choices) { for (const i of choices) {
// @ts-ignore // @ts-ignore
content.push(<MenuItem value={i}>{choices[i]}</MenuItem>); content.push(
<MenuItem key={i} value={i}>
{i}
</MenuItem>,
);
} }
return content; return content;
} };
return ( return (
<> <>
<div style={{ display: 'flex', alignItems: 'center', paddingTop: '10px' }}> <div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
<Select onChange={onChange} value={value} style={{ flex: '1 0 auto' }}> <Select onChange={onChange} value={value} style={{ flex: "1 0 auto" }}>
{getItems(prompt?.options?.choices || [])} {getItems(prompt?.options?.choices || [])}
</Select> </Select>
<Button onClick={submit}>Confirm</Button> <Button onClick={submit} disabled={value === ""}>
Confirm
</Button>
</div> </div>
</> </>
); );