diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2021-04-12 13:09:09 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-12 13:09:09 +0000 |
commit | d80d0f87b82ba4bd74ed9b2bb7354421a28a11b3 (patch) | |
tree | 691185ad88418d0f44c236d0913cf5c425b29b23 /src/console/components/CommandPrompt.tsx | |
parent | ea73c900f66107fd4a5b2f3b05080bcf643c94ea (diff) | |
parent | 8a5bba1da639355a25da8c279a9f1cf0a7300a9f (diff) |
Merge pull request #1098 from ueokande/replace-redux-with-react-hooks
Refactor state management with React Hooks on Console
Diffstat (limited to 'src/console/components/CommandPrompt.tsx')
-rw-r--r-- | src/console/components/CommandPrompt.tsx | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/console/components/CommandPrompt.tsx b/src/console/components/CommandPrompt.tsx new file mode 100644 index 0000000..1b6281b --- /dev/null +++ b/src/console/components/CommandPrompt.tsx @@ -0,0 +1,116 @@ +import React from "react"; +import Completion from "./console/Completion"; +import Input from "./console//Input"; +import styled from "styled-components"; +import { useCompletions, useSelectCompletion } from "../completion/hooks"; +import useAutoResize from "../hooks/useAutoResize"; +import { CompletionProvider } from "../completion/provider"; +import { useExecCommand, useHide } from "../app/hooks"; + +const COMPLETION_MAX_ITEMS = 33; + +const ConsoleWrapper = styled.div` + border-top: 1px solid gray; +`; + +interface Props { + initialInputValue: string; +} + +const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { + const hide = useHide(); + const [inputValue, setInputValue] = React.useState(initialInputValue); + const { completions, updateCompletions } = useCompletions(); + const { + select, + currentValue, + selectNext, + selectPrev, + } = useSelectCompletion(); + const execCommand = useExecCommand(); + + useAutoResize(); + + const onBlur = () => { + hide(); + }; + + const isCancelKey = React.useCallback( + (e: React.KeyboardEvent<HTMLInputElement>) => + e.key === "Escape" || + (e.ctrlKey && e.key === "[") || + (e.ctrlKey && e.key === "c"), + [] + ); + + const isNextKey = React.useCallback( + (e: React.KeyboardEvent<HTMLInputElement>) => + (!e.shiftKey && e.key === "Tab") || (e.ctrlKey && e.key === "n"), + [] + ); + + const isPrevKey = React.useCallback( + (e: React.KeyboardEvent<HTMLInputElement>) => + (e.shiftKey && e.key === "Tab") || (e.ctrlKey && e.key === "p"), + [] + ); + + const isEnterKey = React.useCallback( + (e: React.KeyboardEvent<HTMLInputElement>) => + e.key === "Enter" || (e.ctrlKey && e.key === "m"), + [] + ); + + const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { + if (isCancelKey(e)) { + hide(); + } else if (isEnterKey(e)) { + const value = (e.target as HTMLInputElement).value; + execCommand(value); + hide(); + } else if (isNextKey(e)) { + selectNext(); + } else if (isPrevKey(e)) { + selectPrev(); + } else { + return; + } + + e.stopPropagation(); + e.preventDefault(); + }; + + const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const text = e.target.value; + setInputValue(text); + }; + + React.useEffect(() => { + updateCompletions(inputValue); + }, [inputValue]); + + return ( + <ConsoleWrapper> + <Completion + size={COMPLETION_MAX_ITEMS} + completions={completions} + select={select} + /> + <Input + prompt={":"} + onBlur={onBlur} + onKeyDown={onKeyDown} + onChange={onChange} + value={select == -1 ? inputValue : currentValue} + /> + </ConsoleWrapper> + ); +}; + +const CommandPrompt: React.FC<Props> = ({ initialInputValue }) => ( + <CompletionProvider initialInputValue={initialInputValue}> + <CommandPromptInner initialInputValue={initialInputValue} /> + </CompletionProvider> +); + +export default CommandPrompt; |