some things working

This commit is contained in:
EthanShoeDev
2025-09-17 16:44:16 -04:00
parent b3eb42c348
commit 86ff6762a3
8 changed files with 125 additions and 189 deletions

View File

@@ -1,9 +1,9 @@
<!doctype html>
<html lang="en">
<html style="margin: 0; padding: 0; width: 100vw; height: 100vh">
<head>
<meta charset="UTF-8" />
</head>
<body style="margin: 0; padding: 0; width: 100%; height: 100%">
<body style="margin: 0; padding: 0; width: 100vw; height: 100vh">
<div
id="terminal"
style="margin: 0; padding: 0; width: 100%; height: 100%"

View File

@@ -17,22 +17,24 @@
"preview": "vite preview"
},
"dependencies": {
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"js-base64": "^3.7.8",
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@epic-web/config": "^1.21.3",
"@eslint/js": "^9.35.0",
"@types/react": "~19.1.12",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.2",
"eslint": "^9.35.0",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.4.0",
"@epic-web/config": "^1.21.3",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"typescript": "~5.9.2",
"typescript-eslint": "^8.44.0",
"vite": "6.3.6",

View File

@@ -1,24 +1,30 @@
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { Base64 } from 'js-base64';
import '@xterm/xterm/css/xterm.css';
const decoder = new TextDecoder('utf-8');
const terminal = new Terminal();
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(document.getElementById('terminal')!);
terminal.write('Hello from Xterm.js!');
fitAddon.fit();
window.terminal = terminal;
window.fitAddon = fitAddon;
const postMessage = (arg: string) => {
window.ReactNativeWebView?.postMessage?.(arg);
};
setTimeout(() => {
postMessage('DEBUG: set timeout');
}, 1000);
postMessage('initialized');
}, 10);
terminal.onData((data) => {
const base64Data = Base64.encode(data);
postMessage(base64Data);
});
function terminalWriteBase64(base64Data: string) {
try {
postMessage(`DEBUG: terminalWriteBase64 ${base64Data}`);
const data = new Uint8Array(Buffer.from(base64Data, 'base64'));
postMessage(`DEBUG: terminalWriteBase64 decoded ${decoder.decode(data)}`);
const data = Base64.toUint8Array(base64Data);
terminal.write(data);
} catch (e) {
postMessage(`DEBUG: terminalWriteBase64 error ${e}`);

View File

@@ -2,6 +2,7 @@
interface Window {
terminal?: Terminal;
fitAddon?: FitAddon;
terminalWriteBase64?: (data: string) => void;
ReactNativeWebView?: {
postMessage?: (data: string) => void;

View File

@@ -8,13 +8,19 @@ type StrictOmit<T, K extends keyof T> = Omit<T, K>;
export type XtermWebViewHandle = {
write: (data: Uint8Array) => void;
};
const decoder = new TextDecoder('utf-8');
export function XtermJsWebView({
ref,
onMessage,
...props
}: StrictOmit<ComponentProps<typeof WebView>, 'source' | 'originWhitelist'> & {
}: StrictOmit<
ComponentProps<typeof WebView>,
'source' | 'originWhitelist' | 'onMessage'
> & {
ref: React.RefObject<XtermWebViewHandle | null>;
onMessage?: (
data: { type: 'data'; data: Uint8Array } | { type: 'initialized' },
) => void;
}) {
const webViewRef = useRef<WebView>(null);
@@ -22,17 +28,8 @@ export function XtermJsWebView({
return {
write: (data) => {
const base64Data = Base64.fromUint8Array(data);
console.log('writing rn side', {
base64Data,
dataLength: data.length,
});
console.log(
'try to decode',
decoder.decode(Base64.toUint8Array(base64Data)),
);
webViewRef.current?.injectJavaScript(`
window?.terminalWriteBase64('${base64Data}');
window?.terminalWriteBase64?.('${base64Data}');
`);
},
};
@@ -43,6 +40,15 @@ export function XtermJsWebView({
ref={webViewRef}
originWhitelist={['*']}
source={{ html: htmlString }}
onMessage={(event) => {
const message = event.nativeEvent.data;
if (message === 'initialized') {
onMessage?.({ type: 'initialized' });
return;
}
const data = Base64.toUint8Array(message);
onMessage?.({ type: 'data', data });
}}
{...props}
/>
);