From 580ff01697348f06a2f1127fd2d7a3ddb713aba5 Mon Sep 17 00:00:00 2001 From: Florian Renaut Date: Fri, 22 Aug 2025 10:16:24 +0200 Subject: [PATCH] feat: add sendCommand, improve typing Signed-off-by: Florian Renaut --- src/components/Editor.tsx | 19 ++++++++++++++++--- src/components/Terminal.tsx | 26 +++++++++++++++++--------- src/hooks/editor.tsx | 6 +++++- src/index.tsx | 16 +++++++++++++--- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index dc01e3d..ff959bf 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -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((props, ref) => { const wrapperRef = React.useRef(null); const style = React.useContext(StyleContext); const themeStyles = React.useContext(ThemeContext); @@ -28,7 +32,7 @@ export default function Editor(props: any) { defaultHandler } = props; - const currentLine = useCurrentLine( + const { currentLine, setEditorInput, setProcessCurrentLine } = useCurrentLine( caret, consoleFocused, prompt, @@ -39,6 +43,13 @@ export default function Editor(props: any) { wrapperRef ); + React.useImperativeHandle(ref, () => ({ + sendCommand: (cmd: string) => { + setEditorInput(cmd); + setProcessCurrentLine(true); + } + })); + return (
{welcomeMessage} @@ -46,4 +57,6 @@ export default function Editor(props: any) { {currentLine}
); -} +}); + +export default Editor; diff --git a/src/components/Terminal.tsx b/src/components/Terminal.tsx index e38ba89..7a36c43 100644 --- a/src/components/Terminal.tsx +++ b/src/components/Terminal.tsx @@ -5,11 +5,11 @@ 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 @@ -17,13 +17,15 @@ interface TerminalProps { showControlButtons: boolean controlButtonLabels: string[] prompt: string - commands: Record void> + commands: Record 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 = ({ +const Terminal = React.forwardRef(({ enableInput = true, caret = true, theme = "light", @@ -35,11 +37,12 @@ const Terminal: React.FC = ({ 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); @@ -49,6 +52,7 @@ const Terminal: React.FC = ({ controlButtonLabels={controlButtonLabels}/> : null; const editor = = ({ defaultHandler={defaultHandler} /> + React.useImperativeHandle(ref, () => ({ + sendCommand: editorRef.current.sendCommand + })); + return (
= ({
); -} +}); -export default Terminal; \ No newline at end of file +export default Terminal; diff --git a/src/hooks/editor.tsx b/src/hooks/editor.tsx index 1cdf7df..01fa840 100644 --- a/src/hooks/editor.tsx +++ b/src/hooks/editor.tsx @@ -325,7 +325,11 @@ export const useCurrentLine = ( defaultHandler ); - return currentLine; + return { + currentLine, + setEditorInput, + setProcessCurrentLine, + }; }; export const useScrollToBottom = (changesToWatch: any, wrapperRef: any) => { diff --git a/src/index.tsx b/src/index.tsx index 06a2cc2..024b96e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -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>( + (props: Terminal.TerminalProps, ref) => { + const terminalRef = React.useRef(undefined); + + React.useImperativeHandle(ref, () => ({ + sendCommand: terminalRef.current?.sendCommand + })); + return ( - + ); } +); export const TerminalContextProvider = _TerminalContextProvider; export const TerminalContext = _TerminalContext;