Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
useScrollToBottom,
} from "../hooks/editor";

export default function Editor(props: any) {
export interface EditorHandle {
sendCommand: (command: string) => void;
}

const Editor = React.forwardRef<EditorHandle, any>((props, ref) => {
const wrapperRef = React.useRef(null);
const style = React.useContext(StyleContext);
const themeStyles = React.useContext(ThemeContext);
Expand All @@ -28,7 +32,7 @@ export default function Editor(props: any) {
defaultHandler
} = props;

const currentLine = useCurrentLine(
const { currentLine, setEditorInput, setProcessCurrentLine } = useCurrentLine(
caret,
consoleFocused,
prompt,
Expand All @@ -39,11 +43,20 @@ export default function Editor(props: any) {
wrapperRef
);

React.useImperativeHandle(ref, () => ({
sendCommand: (cmd: string) => {
setEditorInput(cmd);
setProcessCurrentLine(true);
}
}));

return (
<div id={"terminalEditor"} ref={wrapperRef} className={`${style.editor} ${!showControlBar ? style.curvedTop : null} ${showControlBar ? style.editorWithTopBar : null}`} style={{ background: themeStyles.themeBGColor }}>
{welcomeMessage}
{bufferedContent}
{currentLine}
</div>
);
}
});

export default Editor;
26 changes: 17 additions & 9 deletions src/components/Terminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@ import { ThemeContext } from "../contexts/ThemeContext";
import { useClickOutsideEvent } from "../hooks/terminal";

import Controls from "./Controls";
import Editor from "./Editor";
import Editor, { EditorHandle } from "./Editor";

import Utils from "../common/Utils";

interface TerminalProps {
export interface TerminalProps {
enableInput: boolean
caret: boolean
theme: string
showControlBar: boolean
showControlButtons: boolean
controlButtonLabels: string[]
prompt: string
commands: Record<string, (...args: never) => void>
commands: Record<string, string | ((...args: never) => void)>
welcomeMessage: string | (() => void) | React.ReactNode
errorMessage: string | ((...args: never) => void) | React.ReactNode
defaultHandler: ((...args: never) => void) | null
};
defaultHandler: ((...args: never) => void) | null,
}

export type TerminalHandle = EditorHandle;

const Terminal: React.FC<TerminalProps> = ({
const Terminal = React.forwardRef<TerminalHandle, TerminalProps>(({
enableInput = true,
caret = true,
theme = "light",
Expand All @@ -35,11 +37,12 @@ const Terminal: React.FC<TerminalProps> = ({
welcomeMessage = "",
errorMessage = "not found!",
defaultHandler = null,
}) => {
}, ref) => {
const wrapperRef = React.useRef(null);
const [consoleFocused, setConsoleFocused] = React.useState(!Utils.isMobile());
const style = React.useContext(StyleContext);
const themeStyles = React.useContext(ThemeContext);
const editorRef = React.useRef(undefined);

useClickOutsideEvent(wrapperRef, consoleFocused, setConsoleFocused);

Expand All @@ -49,6 +52,7 @@ const Terminal: React.FC<TerminalProps> = ({
controlButtonLabels={controlButtonLabels}/> : null;

const editor = <Editor
ref={editorRef}
caret={caret}
consoleFocused={consoleFocused}
prompt={prompt}
Expand All @@ -60,6 +64,10 @@ const Terminal: React.FC<TerminalProps> = ({
defaultHandler={defaultHandler}
/>

React.useImperativeHandle(ref, () => ({
sendCommand: editorRef.current.sendCommand
}));

return (
<div
ref={wrapperRef}
Expand All @@ -73,6 +81,6 @@ const Terminal: React.FC<TerminalProps> = ({
</div>
</div>
);
}
});

export default Terminal;
export default Terminal;
6 changes: 5 additions & 1 deletion src/hooks/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,11 @@ export const useCurrentLine = (
defaultHandler
);

return currentLine;
return {
currentLine,
setEditorInput,
setProcessCurrentLine,
};
};

export const useScrollToBottom = (changesToWatch: any, wrapperRef: any) => {
Expand Down
16 changes: 13 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import * as React from "react";
import * as Terminal from "./components/Terminal";
import * as ContextProvider from "./contexts";
import {
import {
TerminalContextProvider as _TerminalContextProvider,
TerminalContext as _TerminalContext
} from "./contexts/TerminalContext";

export function ReactTerminal(props: any): any {
export type ReactTerminalHandle = Terminal.TerminalHandle;

export const ReactTerminal = React.forwardRef<ReactTerminalHandle, Partial<Terminal.TerminalProps>>(
(props: Terminal.TerminalProps, ref) => {
const terminalRef = React.useRef(undefined);

React.useImperativeHandle(ref, () => ({
sendCommand: terminalRef.current?.sendCommand
}));

return (
<ContextProvider.default>
<Terminal.default {...props} />
<Terminal.default {...props} ref={terminalRef} />
</ContextProvider.default>
);
}
);

export const TerminalContextProvider = _TerminalContextProvider;
export const TerminalContext = _TerminalContext;
Expand Down