@@ -5,8 +5,6 @@ import * as React from "react";
55
66import { base64ToArray , stringToBase64 } from "@/util/base64" ;
77
8- const TermWriteEventName = "tsunami:termwrite" ;
9-
108type TermSize = {
119 rows : number ;
1210 cols : number ;
@@ -18,9 +16,9 @@ type TermInputPayload = {
1816 data64 ?: string ;
1917} ;
2018
21- type TermWritePayload = {
22- id : string ;
23- data64 : string ;
19+ export type TsunamiTermElem = HTMLDivElement & {
20+ __termWrite : ( data64 : string ) => void ;
21+ __termFocus : ( ) => void ;
2422} ;
2523
2624async function sendTermInput ( payload : TermInputPayload ) {
@@ -41,13 +39,28 @@ const TsunamiTerm = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDi
4139 ref
4240) {
4341 const { id, ...outerProps } = props ;
44- const outerRef = React . useRef < HTMLDivElement > ( null ) ;
42+ const outerRef = React . useRef < TsunamiTermElem > ( null ) ;
4543 const termRef = React . useRef < HTMLDivElement > ( null ) ;
4644 const terminalRef = React . useRef < Terminal | null > ( null ) ;
4745
4846 const setOuterRef = React . useCallback (
49- ( elem : HTMLDivElement ) => {
47+ ( elem : TsunamiTermElem ) => {
5048 outerRef . current = elem ;
49+ if ( elem != null ) {
50+ elem . __termWrite = ( data64 : string ) => {
51+ if ( data64 == null || data64 === "" ) {
52+ return ;
53+ }
54+ try {
55+ terminalRef . current ?. write ( base64ToArray ( data64 ) ) ;
56+ } catch ( error ) {
57+ console . error ( "Failed to write to terminal:" , error ) ;
58+ }
59+ } ;
60+ elem . __termFocus = ( ) => {
61+ terminalRef . current ?. focus ( ) ;
62+ } ;
63+ }
5164 if ( typeof ref === "function" ) {
5265 ref ( elem ) ;
5366 return ;
@@ -114,29 +127,27 @@ const TsunamiTerm = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDi
114127 } ;
115128 } , [ id ] ) ;
116129
117- React . useEffect ( ( ) => {
118- const handleTermWrite = ( event : Event ) => {
119- const detail = ( event as CustomEvent < TermWritePayload > ) . detail ;
120- if ( detail == null || detail . id !== id || detail . data64 == null || detail . data64 === "" ) {
121- return ;
122- }
123- try {
124- terminalRef . current ?. write ( base64ToArray ( detail . data64 ) ) ;
125- } catch ( error ) {
126- console . error ( "Failed to process term write event:" , error ) ;
127- }
128- } ;
129- window . addEventListener ( TermWriteEventName , handleTermWrite ) ;
130- return ( ) => {
131- window . removeEventListener ( TermWriteEventName , handleTermWrite ) ;
132- } ;
133- } , [ id ] ) ;
130+ const handleFocus = React . useCallback (
131+ ( e : React . FocusEvent < HTMLDivElement > ) => {
132+ terminalRef . current ?. focus ( ) ;
133+ outerProps . onFocus ?.( e ) ;
134+ } ,
135+ [ outerProps . onFocus ]
136+ ) ;
137+
138+ const handleBlur = React . useCallback (
139+ ( e : React . FocusEvent < HTMLDivElement > ) => {
140+ terminalRef . current ?. blur ( ) ;
141+ outerProps . onBlur ?.( e ) ;
142+ } ,
143+ [ outerProps . onBlur ]
144+ ) ;
134145
135146 return (
136- < div { ...outerProps } id = { id } ref = { setOuterRef } >
147+ < div { ...outerProps } id = { id } ref = { setOuterRef as React . RefCallback < HTMLDivElement > } onFocus = { handleFocus } onBlur = { handleBlur } >
137148 < div ref = { termRef } className = "w-full h-full" />
138149 </ div >
139150 ) ;
140151} ) ;
141152
142- export { TermWriteEventName , TsunamiTerm } ;
153+ export { TsunamiTerm } ;
0 commit comments