Spaces:
Running
Running
| import { useEffect, useRef } from "react"; | |
| import { Terminal } from "xterm"; | |
| import { FitAddon } from "xterm-addon-fit"; | |
| import "xterm/css/xterm.css"; | |
| export default function XTerm({ onData, output }) { | |
| const termRef = useRef(null); | |
| const fitAddon = new FitAddon(); | |
| useEffect(() => { | |
| const term = new Terminal({ | |
| cursorBlink: true, | |
| fontSize: 14, | |
| theme: { | |
| background: "#1e1e1e", | |
| foreground: "#ffffff", | |
| }, | |
| }); | |
| termRef.current = term; | |
| term.loadAddon(fitAddon); | |
| term.open(document.getElementById("terminal-container")); | |
| fitAddon.fit(); | |
| term.onData((data) => { | |
| // Echo user input (like real terminals) | |
| term.write(data); | |
| // When ENTER pressed, send full line to parent | |
| if (data === "\r") { | |
| const line = term._core.buffer.xtermBuffer.active.getLine( | |
| term.buffer.active.cursorY | |
| ).translateToString().trim(); | |
| onData(line); | |
| } | |
| }); | |
| return () => term.dispose(); | |
| }, []); | |
| // Print backend output into terminal | |
| useEffect(() => { | |
| if (output) { | |
| termRef.current?.writeln("\r\n" + output); | |
| } | |
| }, [output]); | |
| return ( | |
| <div | |
| id="terminal-container" | |
| style={{ | |
| width: "100%", | |
| height: "180px", | |
| background: "#1e1e1e", | |
| borderTop: "1px solid #333", | |
| }} | |
| ></div> | |
| ); | |
| } | |