aboutsummaryrefslogtreecommitdiff
path: root/src/console/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/console/components')
-rw-r--r--src/console/components/CommandPrompt.tsx116
-rw-r--r--src/console/components/Console.tsx288
-rw-r--r--src/console/components/ErrorMessage.tsx15
-rw-r--r--src/console/components/FindPrompt.tsx58
-rw-r--r--src/console/components/InfoMessage.tsx15
-rw-r--r--src/console/components/Theme.ts53
-rw-r--r--src/console/components/console/Completion.tsx136
-rw-r--r--src/console/components/console/CompletionItem.tsx8
-rw-r--r--src/console/components/console/CompletionTitle.tsx10
-rw-r--r--src/console/components/console/Input.tsx61
-rw-r--r--src/console/components/console/Message.tsx33
11 files changed, 334 insertions, 459 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;
diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx
index 18a6632..db18fa0 100644
--- a/src/console/components/Console.tsx
+++ b/src/console/components/Console.tsx
@@ -1,251 +1,39 @@
-import { connect } from "react-redux";
import React from "react";
-import Input from "./console/Input";
-import Completion from "./console/Completion";
-import Message from "./console/Message";
-import * as consoleActions from "../../console/actions/console";
-import { State as AppState } from "../reducers";
-import CommandLineParser, {
- InputPhase,
-} from "../commandline/CommandLineParser";
-import { Command } from "../../shared/Command";
-import ColorScheme from "../../shared/ColorScheme";
-import { LightTheme, DarkTheme } from "./Theme";
-import styled from "./Theme";
-import { ThemeProvider } from "styled-components";
-import ConsoleFrameClient from "../clients/ConsoleFrameClient";
-
-const ConsoleWrapper = styled.div`
- border-top: 1px solid gray;
-`;
-
-const COMPLETION_MAX_ITEMS = 33;
-
-type StateProps = ReturnType<typeof mapStateToProps>;
-interface DispatchProps {
- dispatch: (action: any) => void;
-}
-type Props = StateProps & DispatchProps;
-
-class Console extends React.Component<Props> {
- private input: React.RefObject<Input>;
-
- private commandLineParser: CommandLineParser = new CommandLineParser();
- private consoleFrameClient = new ConsoleFrameClient();
-
- constructor(props: Props) {
- super(props);
-
- this.input = React.createRef();
- }
-
- onBlur() {
- if (this.props.mode === "command" || this.props.mode === "find") {
- return this.props.dispatch(consoleActions.hideCommand());
- }
- }
-
- doEnter(e: React.KeyboardEvent<HTMLInputElement>) {
- e.stopPropagation();
- e.preventDefault();
-
- const value = (e.target as HTMLInputElement).value;
- if (this.props.mode === "command") {
- return this.props.dispatch(consoleActions.enterCommand(value));
- } else if (this.props.mode === "find") {
- return this.props.dispatch(
- consoleActions.enterFind(value === "" ? undefined : value)
- );
- }
- }
-
- selectNext(e: React.KeyboardEvent<HTMLInputElement>) {
- this.props.dispatch(consoleActions.completionNext());
- e.stopPropagation();
- e.preventDefault();
- }
-
- selectPrev(e: React.KeyboardEvent<HTMLInputElement>) {
- this.props.dispatch(consoleActions.completionPrev());
- e.stopPropagation();
- e.preventDefault();
- }
-
- onKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
- switch (e.key) {
- case "Escape":
- return this.props.dispatch(consoleActions.hideCommand());
- case "Enter":
- return this.doEnter(e);
- case "Tab":
- if (e.shiftKey) {
- this.props.dispatch(consoleActions.completionPrev());
- } else {
- this.props.dispatch(consoleActions.completionNext());
- }
- e.stopPropagation();
- e.preventDefault();
- break;
- case "[":
- if (e.ctrlKey) {
- e.preventDefault();
- return this.props.dispatch(consoleActions.hideCommand());
- }
- break;
- case "c":
- if (e.ctrlKey) {
- e.preventDefault();
- return this.props.dispatch(consoleActions.hideCommand());
- }
- break;
- case "m":
- if (e.ctrlKey) {
- return this.doEnter(e);
- }
- break;
- case "n":
- if (e.ctrlKey) {
- this.selectNext(e);
- }
- break;
- case "p":
- if (e.ctrlKey) {
- this.selectPrev(e);
- }
- break;
- }
- }
-
- onChange(e: React.ChangeEvent<HTMLInputElement>) {
- const text = e.target.value;
- this.props.dispatch(consoleActions.setConsoleText(text));
- if (this.props.mode !== "command") {
- return;
- }
- this.updateCompletions(text);
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.mode !== "command" && this.props.mode === "command") {
- this.updateCompletions(this.props.consoleText);
- this.focus();
- } else if (prevProps.mode !== "find" && this.props.mode === "find") {
- this.focus();
- }
-
- const {
- scrollWidth: width,
- scrollHeight: height,
- } = document.getElementById("vimvixen-console")!;
- this.consoleFrameClient.resize(width, height);
- }
-
- render() {
- let theme = this.props.colorscheme;
- if (this.props.colorscheme === ColorScheme.System) {
- if (
- window.matchMedia &&
- window.matchMedia("(prefers-color-scheme: dark)").matches
- ) {
- theme = ColorScheme.Dark;
- } else {
- theme = ColorScheme.Light;
- }
- }
-
- switch (this.props.mode) {
- case "command":
- case "find":
- return (
- <ThemeProvider
- theme={theme === ColorScheme.Dark ? DarkTheme : LightTheme}
- >
- <ConsoleWrapper>
- <Completion
- size={COMPLETION_MAX_ITEMS}
- completions={this.props.completions}
- select={this.props.select}
- />
- <Input
- ref={this.input}
- mode={this.props.mode}
- onBlur={this.onBlur.bind(this)}
- onKeyDown={this.onKeyDown.bind(this)}
- onChange={this.onChange.bind(this)}
- value={this.props.consoleText}
- />
- </ConsoleWrapper>
- </ThemeProvider>
- );
- case "info":
- case "error":
- return (
- <ThemeProvider
- theme={theme === ColorScheme.Dark ? DarkTheme : LightTheme}
- >
- <Message mode={this.props.mode}>{this.props.messageText}</Message>
- </ThemeProvider>
- );
- default:
- return null;
- }
- }
-
- async focus() {
- this.props.dispatch(consoleActions.setColorScheme());
-
- window.focus();
- if (this.input.current) {
- this.input.current.focus();
- }
- }
-
- private updateCompletions(text: string) {
- const phase = this.commandLineParser.inputPhase(text);
- if (phase === InputPhase.OnCommand) {
- return this.props.dispatch(consoleActions.getCommandCompletions(text));
- } else {
- const cmd = this.commandLineParser.parse(text);
- switch (cmd.command) {
- case Command.Open:
- case Command.TabOpen:
- case Command.WindowOpen:
- this.props.dispatch(
- consoleActions.getOpenCompletions(
- this.props.completionTypes,
- text,
- cmd.command,
- cmd.args
- )
- );
- break;
- case Command.Buffer:
- this.props.dispatch(
- consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)
- );
- break;
- case Command.BufferDelete:
- case Command.BuffersDelete:
- this.props.dispatch(
- consoleActions.getTabCompletions(text, cmd.command, cmd.args, true)
- );
- break;
- case Command.BufferDeleteForce:
- case Command.BuffersDeleteForce:
- this.props.dispatch(
- consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)
- );
- break;
- case Command.Set:
- this.props.dispatch(
- consoleActions.getPropertyCompletions(text, cmd.command, cmd.args)
- );
- break;
- }
- }
- }
-}
-
-const mapStateToProps = (state: AppState) => ({ ...state });
-
-export default connect(mapStateToProps)(Console);
+import FindPrompt from "./FindPrompt";
+import CommandPrompt from "./CommandPrompt";
+import InfoMessage from "./InfoMessage";
+import ErrorMessage from "./ErrorMessage";
+import { useColorSchemeRefresh } from "../colorscheme/hooks";
+import {
+ useCommandMode,
+ useErrorMessage,
+ useFindMode,
+ useInfoMessage,
+} from "../app/hooks";
+
+const Console: React.FC = () => {
+ const refreshColorScheme = useColorSchemeRefresh();
+ const { visible: visibleCommand, initialInputValue } = useCommandMode();
+ const { visible: visibleFind } = useFindMode();
+ const { visible: visibleInfo, message: infoMessage } = useInfoMessage();
+ const { visible: visibleError, message: errorMessage } = useErrorMessage();
+
+ React.useEffect(() => {
+ if (visibleCommand || visibleFind || visibleInfo || visibleError) {
+ refreshColorScheme();
+ }
+ }, [visibleCommand, visibleFind, visibleInfo, visibleError]);
+
+ if (visibleCommand) {
+ return <CommandPrompt initialInputValue={initialInputValue} />;
+ } else if (visibleFind) {
+ return <FindPrompt />;
+ } else if (visibleInfo) {
+ return <InfoMessage>{infoMessage}</InfoMessage>;
+ } else if (visibleError) {
+ return <ErrorMessage>{errorMessage}</ErrorMessage>;
+ }
+ return null;
+};
+
+export default Console;
diff --git a/src/console/components/ErrorMessage.tsx b/src/console/components/ErrorMessage.tsx
new file mode 100644
index 0000000..f8d5ae7
--- /dev/null
+++ b/src/console/components/ErrorMessage.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import styled from "../colorscheme/styled";
+
+const Wrapper = styled.p`
+ border-top: 1px solid gray;
+ background-color: ${({ theme }) => theme.consoleErrorBackground};
+ color: ${({ theme }) => theme.consoleErrorForeground};
+ font-weight: bold;
+`;
+
+const ErrorMessage: React.FC = ({ children }) => {
+ return <Wrapper role="alert">{children}</Wrapper>;
+};
+
+export default ErrorMessage;
diff --git a/src/console/components/FindPrompt.tsx b/src/console/components/FindPrompt.tsx
new file mode 100644
index 0000000..c437d16
--- /dev/null
+++ b/src/console/components/FindPrompt.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import Input from "./console/Input";
+import styled from "styled-components";
+import useAutoResize from "../hooks/useAutoResize";
+import { useExecFind, useHide } from "../app/hooks";
+
+const ConsoleWrapper = styled.div`
+ border-top: 1px solid gray;
+`;
+
+const FindPrompt: React.FC = () => {
+ const [inputValue, setInputValue] = React.useState("");
+ const hide = useHide();
+ const execFind = useExecFind();
+
+ const onBlur = () => {
+ hide();
+ };
+
+ useAutoResize();
+
+ const doEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ const value = (e.target as HTMLInputElement).value;
+ execFind(value === "" ? undefined : value);
+ };
+
+ const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ switch (e.key) {
+ case "Escape":
+ hide();
+ break;
+ case "Enter":
+ doEnter(e);
+ break;
+ }
+ };
+
+ const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ setInputValue(e.target.value);
+ };
+
+ return (
+ <ConsoleWrapper>
+ <Input
+ prompt={"/"}
+ onBlur={onBlur}
+ onKeyDown={onKeyDown}
+ onChange={onChange}
+ value={inputValue}
+ />
+ </ConsoleWrapper>
+ );
+};
+
+export default FindPrompt;
diff --git a/src/console/components/InfoMessage.tsx b/src/console/components/InfoMessage.tsx
new file mode 100644
index 0000000..ccd9bcf
--- /dev/null
+++ b/src/console/components/InfoMessage.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import styled from "../colorscheme/styled";
+
+const Wrapper = styled.p`
+ border-top: 1px solid gray;
+ background-color: ${({ theme }) => theme.consoleInfoBackground};
+ color: ${({ theme }) => theme.consoleInfoForeground};
+ font-weight: normal;
+`;
+
+const InfoMessage: React.FC = ({ children }) => {
+ return <Wrapper role="status">{children}</Wrapper>;
+};
+
+export default InfoMessage;
diff --git a/src/console/components/Theme.ts b/src/console/components/Theme.ts
deleted file mode 100644
index dd7baa5..0000000
--- a/src/console/components/Theme.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import baseStyled, { ThemedStyledInterface } from "styled-components";
-
-type Theme = {
- completionTitleBackground: string;
- completionTitleForeground: string;
- completionItemBackground: string;
- completionItemForeground: string;
- completionItemDescriptionForeground: string;
- completionSelectedBackground: string;
- completionSelectedForeground: string;
- commandBackground: string;
- commandForeground: string;
- consoleErrorBackground: string;
- consoleErrorForeground: string;
- consoleInfoBackground: string;
- consoleInfoForeground: string;
-};
-
-export const LightTheme: Theme = {
- completionTitleBackground: "lightgray",
- completionTitleForeground: "#000000",
- completionItemBackground: "#ffffff",
- completionItemForeground: "#000000",
- completionItemDescriptionForeground: "#008000",
- completionSelectedBackground: "#ffff00",
- completionSelectedForeground: "#000000",
- commandBackground: "#ffffff",
- commandForeground: "#000000",
- consoleErrorBackground: "#ff0000",
- consoleErrorForeground: "#ffffff",
- consoleInfoBackground: "#ffffff",
- consoleInfoForeground: "#018786",
-};
-
-export const DarkTheme: Theme = {
- completionTitleBackground: "#052027",
- completionTitleForeground: "white",
- completionItemBackground: "#2f474f",
- completionItemForeground: "white",
- completionItemDescriptionForeground: "#86fab0",
- completionSelectedBackground: "#eeff41",
- completionSelectedForeground: "#000000",
- commandBackground: "#052027",
- commandForeground: "white",
- consoleErrorBackground: "red",
- consoleErrorForeground: "white",
- consoleInfoBackground: "#052027",
- consoleInfoForeground: "#ffffff",
-};
-
-const styled = baseStyled as ThemedStyledInterface<Theme>;
-
-export default styled;
diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx
index 09ae278..ed271aa 100644
--- a/src/console/components/console/Completion.tsx
+++ b/src/console/components/console/Completion.tsx
@@ -19,97 +19,85 @@ interface Props {
completions: Group[];
}
-interface State {
- viewOffset: number;
- select: number;
-}
-
-class Completion extends React.Component<Props, State> {
- constructor(props: Props) {
- super(props);
- this.state = { viewOffset: 0, select: -1 };
- }
+const Completion: React.FC<Props> = ({ select, size, completions }) => {
+ const [viewOffset, setViewOffset] = React.useState(0);
+ const [prevSelect, setPrevSelect] = React.useState(-1);
- static getDerivedStateFromProps(nextProps: Props, prevState: State) {
- if (prevState.select === nextProps.select) {
- return null;
+ React.useEffect(() => {
+ if (select === prevSelect) {
+ return;
}
const viewSelect = (() => {
let index = 0;
- for (let i = 0; i < nextProps.completions.length; ++i) {
+ for (let i = 0; i < completions.length; ++i) {
++index;
- const g = nextProps.completions[i];
- if (nextProps.select + i + 1 < index + g.items.length) {
- return nextProps.select + i + 1;
+ const g = completions[i];
+ if (select + i + 1 < index + g.items.length) {
+ return select + i + 1;
}
index += g.items.length;
}
return -1;
})();
- let viewOffset = 0;
- if (nextProps.select < 0) {
- viewOffset = 0;
- } else if (prevState.select < nextProps.select) {
- viewOffset = Math.max(
- prevState.viewOffset,
- viewSelect - nextProps.size + 1
- );
- } else if (prevState.select > nextProps.select) {
- viewOffset = Math.min(prevState.viewOffset, viewSelect);
- }
- return { viewOffset, select: nextProps.select };
- }
+ const nextViewOffset = (() => {
+ if (prevSelect < select) {
+ return Math.max(viewOffset, viewSelect - size + 1);
+ } else if (prevSelect > select) {
+ return Math.min(viewOffset, viewSelect);
+ }
+ return 0;
+ })();
+
+ setPrevSelect(select);
+ setViewOffset(nextViewOffset);
+ }, [select]);
- render() {
- let itemIndex = 0;
- let viewIndex = 0;
- const groups: Array<JSX.Element> = [];
- const viewOffset = this.state.viewOffset;
- const viewSize = this.props.size;
+ let itemIndex = 0;
+ let viewIndex = 0;
+ const groups: Array<JSX.Element> = [];
- this.props.completions.forEach((group, groupIndex) => {
- const items = [];
- const title = (
- <CompletionTitle
- id={`title-${groupIndex}`}
- key={`group-${groupIndex}`}
- shown={viewOffset <= viewIndex && viewIndex < viewOffset + viewSize}
- title={group.name}
+ completions.forEach((group, groupIndex) => {
+ const items = [];
+ const title = (
+ <CompletionTitle
+ id={`title-${groupIndex}`}
+ key={`group-${groupIndex}`}
+ shown={viewOffset <= viewIndex && viewIndex < viewOffset + size}
+ title={group.name}
+ />
+ );
+ ++viewIndex;
+ for (const item of group.items) {
+ items.push(
+ <CompletionItem
+ shown={viewOffset <= viewIndex && viewIndex < viewOffset + size}
+ key={`item-${itemIndex}`}
+ icon={item.icon}
+ caption={item.caption}
+ url={item.url}
+ highlight={itemIndex === select}
+ aria-selected={itemIndex === select}
+ role="menuitem"
/>
);
++viewIndex;
- for (const item of group.items) {
- items.push(
- <CompletionItem
- shown={viewOffset <= viewIndex && viewIndex < viewOffset + viewSize}
- key={`item-${itemIndex}`}
- icon={item.icon}
- caption={item.caption}
- url={item.url}
- highlight={itemIndex === this.props.select}
- aria-selected={itemIndex === this.props.select}
- role="menuitem"
- />
- );
- ++viewIndex;
- ++itemIndex;
- }
- groups.push(
- <div
- key={`group-${groupIndex}`}
- role="group"
- aria-describedby={`title-${groupIndex}`}
- >
- {title}
- <ul>{items}</ul>
- </div>
- );
- });
+ ++itemIndex;
+ }
+ groups.push(
+ <div
+ key={`group-${groupIndex}`}
+ role="group"
+ aria-describedby={`title-${groupIndex}`}
+ >
+ {title}
+ <ul>{items}</ul>
+ </div>
+ );
+ });
- return <div role="menu">{groups}</div>;
- }
-}
+ return <div role="menu">{groups}</div>;
+};
export default Completion;
diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx
index 5f2f9f6..2de1375 100644
--- a/src/console/components/console/CompletionItem.tsx
+++ b/src/console/components/console/CompletionItem.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import styled from "../Theme";
+import styled from "../../colorscheme/styled";
const Container = styled.li<{
shown: boolean;
@@ -38,7 +38,7 @@ const Description = styled.span`
overflow: hidden;
`;
-interface Props {
+interface Props extends React.HTMLAttributes<HTMLElement> {
shown: boolean;
highlight: boolean;
caption?: string;
@@ -46,9 +46,7 @@ interface Props {
icon?: string;
}
-const CompletionItem: React.FC<React.HTMLAttributes<HTMLElement> & Props> = (
- props
-) => (
+const CompletionItem: React.FC<Props> = (props) => (
<Container
icon={props.icon || ""}
aria-labelledby={`completion-item-${props.caption}`}
diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx
index ec2fc8b..4018b3f 100644
--- a/src/console/components/console/CompletionTitle.tsx
+++ b/src/console/components/console/CompletionTitle.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import styled from "../Theme";
+import styled from "../../colorscheme/styled";
const Li = styled.li<{ shown: boolean }>`
display: ${({ shown }) => (shown ? "display" : "none")};
@@ -10,13 +10,13 @@ const Li = styled.li<{ shown: boolean }>`
padding: 0;
`;
-interface Props {
+interface Props extends React.HTMLAttributes<HTMLElement> {
shown: boolean;
title: string;
}
-const CompletionTitle: React.FC<React.HTMLAttributes<HTMLElement> & Props> = (
- props
-) => <Li {...props}>{props.title}</Li>;
+const CompletionTitle: React.FC<Props> = (props) => (
+ <Li {...props}>{props.title}</Li>
+);
export default CompletionTitle;
diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx
index 448b096..442bd30 100644
--- a/src/console/components/console/Input.tsx
+++ b/src/console/components/console/Input.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import styled from "../Theme";
+import styled from "../../colorscheme/styled";
const Container = styled.div`
background-color: ${({ theme }) => theme.commandBackground};
@@ -19,49 +19,32 @@ const InputInner = styled.input`
`;
interface Props {
- mode: string;
+ prompt: string;
value: string;
onBlur: (e: React.FocusEvent<HTMLInputElement>) => void;
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}
-class Input extends React.Component<Props> {
- private input: React.RefObject<HTMLInputElement>;
-
- constructor(props: Props) {
- super(props);
-
- this.input = React.createRef();
- }
-
- focus() {
- if (this.input.current) {
- this.input.current.focus();
- }
- }
-
- render() {
- let prompt = "";
- if (this.props.mode === "command") {
- prompt = ":";
- } else if (this.props.mode === "find") {
- prompt = "/";
- }
-
- return (
- <Container>
- <Prompt>{prompt}</Prompt>
- <InputInner
- ref={this.input}
- onBlur={this.props.onBlur}
- onKeyDown={this.props.onKeyDown}
- onChange={this.props.onChange}
- value={this.props.value}
- />
- </Container>
- );
- }
-}
+const Input: React.FC<Props> = (props) => {
+ const input = React.useRef<HTMLInputElement>(null);
+
+ React.useEffect(() => {
+ input?.current?.focus();
+ }, []);
+
+ return (
+ <Container>
+ <Prompt>{props.prompt}</Prompt>
+ <InputInner
+ ref={input}
+ onBlur={props.onBlur}
+ onKeyDown={props.onKeyDown}
+ onChange={props.onChange}
+ value={props.value}
+ />
+ </Container>
+ );
+};
export default Input;
diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx
deleted file mode 100644
index 73498fd..0000000
--- a/src/console/components/console/Message.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from "react";
-import styled from "../Theme";
-
-const Error = styled.p`
- border-top: 1px solid gray;
- background-color: ${({ theme }) => theme.consoleErrorBackground};
- color: ${({ theme }) => theme.consoleErrorForeground};
- font-weight: bold;
-`;
-
-const Info = styled.p`
- border-top: 1px solid gray;
- background-color: ${({ theme }) => theme.consoleInfoBackground};
- color: ${({ theme }) => theme.consoleInfoForeground};
- font-weight: normal;
-`;
-
-interface Props {
- mode: string;
- children: string;
-}
-
-const Message: React.FC<Props> = ({ mode, children }) => {
- switch (mode) {
- case "error":
- return <Error role="alert">{children}</Error>;
- case "info":
- return <Info role="status">{children}</Info>;
- }
- return null;
-};
-
-export default Message;