84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
// src/components/Terminal.tsx
|
|
import React, { useEffect, useRef } from 'react';
|
|
import { Terminal } from 'xterm';
|
|
import { FitAddon } from 'xterm-addon-fit';
|
|
import 'xterm/css/xterm.css';
|
|
|
|
|
|
const useTerminalResize = (terminalRef: React.RefObject<HTMLDivElement>, fitAddon: FitAddon) => {
|
|
useEffect(() => {
|
|
const handleResize = () => {
|
|
if (fitAddon && terminalRef.current) {
|
|
fitAddon.fit();
|
|
}
|
|
};
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
// Fit the terminal initially
|
|
handleResize();
|
|
|
|
return () => {
|
|
window.removeEventListener('resize', handleResize);
|
|
};
|
|
}, [terminalRef, fitAddon]);
|
|
};
|
|
|
|
|
|
function TerminalComponent (p: {websocket: string|null}) {
|
|
const {websocket} = p
|
|
const terminalRef = useRef<HTMLDivElement>(null);
|
|
const terminal = useRef<Terminal | null>(null);
|
|
const fitAddon = useRef<FitAddon | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (terminalRef.current) {
|
|
terminal.current = new Terminal();
|
|
fitAddon.current = new FitAddon();
|
|
terminal.current.loadAddon(fitAddon.current);
|
|
terminal.current.open(terminalRef.current);
|
|
fitAddon.current.fit();
|
|
if (websocket == null){
|
|
|
|
return ()=>{
|
|
terminal.current?.dispose();
|
|
}
|
|
}
|
|
|
|
const socket = new WebSocket(websocket);
|
|
|
|
socket.onerror = (ev)=>{
|
|
console.log(ev)
|
|
}
|
|
|
|
socket.addEventListener('open', () => {
|
|
socket.send(JSON.stringify({CommandType: 'resize', Arguments: `${terminal.current?.rows}x${terminal.current?.cols}`}));
|
|
});
|
|
|
|
terminal.current.onResize(({cols, rows})=>{
|
|
socket.send(JSON.stringify({CommandType: 'resize', Arguments: `${rows}x${cols}`}));
|
|
})
|
|
|
|
socket.addEventListener('message', (event) => {
|
|
terminal.current?.write(JSON.parse(event.data));
|
|
});
|
|
|
|
terminal.current.onData((data) => {
|
|
socket.send(JSON.stringify({CommandType: 'insert', Arguments: data}));
|
|
});
|
|
|
|
return () => {
|
|
console.log("closed websocket")
|
|
terminal.current?.dispose();
|
|
socket.close();
|
|
};
|
|
}
|
|
}, []);
|
|
|
|
useTerminalResize(terminalRef, fitAddon.current!)
|
|
|
|
return <div ref={terminalRef} style={{ width: '100%', height: '100%' }}></div>;
|
|
};
|
|
|
|
export default TerminalComponent;
|