ya-webadb/packages/demo/src/Shell.tsx
2020-09-14 13:15:03 +08:00

76 lines
2.2 KiB
TypeScript

import { WebAdb } from '@yume-chan/webadb';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useRouteMatch } from 'react-router-dom';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
// import { SearchAddon } from 'xterm-addon-search';
import 'xterm/css/xterm.css';
import ResizeObserver from './ResizeObserver';
export default function Shell({ device }: { device?: WebAdb }): JSX.Element | null {
const routeMatch = useRouteMatch();
const [cached, setCached] = useState(false);
useEffect(() => {
setCached(true);
}, [routeMatch]);
const terminalRef = useRef<Terminal>();
const fitAddonRef = useRef<FitAddon>();
const handleContainerRef = useCallback((element: HTMLDivElement | null) => {
if (!element) {
return;
}
const terminal = new Terminal({
scrollback: 9001,
});
const fitAddon = new FitAddon();
fitAddonRef.current = fitAddon;
terminal.loadAddon(fitAddon);
terminalRef.current = terminal;
terminal.open(element);
fitAddon.fit();
}, []);
useEffect(() => {
return () => terminalRef.current?.dispose();
}, []);
useEffect(() => {
if (!device || !terminalRef.current) {
return;
}
(async () => {
const shell = await device.shell();
const textEncoder = new TextEncoder();
terminalRef.current!.onData(data => {
const { buffer } = textEncoder.encode(data);
shell.write(buffer);
});
shell.onData(data => {
terminalRef.current!.write(new Uint8Array(data));
});
})();
return () => {
terminalRef.current!.reset();
terminalRef.current!.clear();
};
}, [device, terminalRef.current]);
const handleResize = useCallback(() => {
fitAddonRef.current?.fit();
}, []);
if (!cached) {
return null;
}
return (
<ResizeObserver onResize={handleResize}>
<div ref={handleContainerRef} style={{ height: '100%' }} />
</ResizeObserver>
)
}