@@ -565,13 +565,16 @@ function ExcalidrawApp() {
565565 const [ elements , setElements ] = useState < any [ ] > ( [ ] ) ;
566566 const [ userEdits , setUserEdits ] = useState < any [ ] | null > ( null ) ;
567567 const [ containerHeight , setContainerHeight ] = useState < number | null > ( null ) ;
568+ const [ canFullscreen , setCanFullscreen ] = useState ( false ) ;
569+ const [ containerMaxHeight , setContainerMaxHeight ] = useState < number | null > ( null ) ;
568570 const [ editorReady , setEditorReady ] = useState ( false ) ;
569571 const [ excalidrawApi , setExcalidrawApi ] = useState < any > ( null ) ;
570572 const [ editorSettled , setEditorSettled ] = useState ( false ) ;
571573 const appRef = useRef < App | null > ( null ) ;
572574 const svgViewportRef = useRef < ViewportRect | null > ( null ) ;
573575 const elementsRef = useRef < any [ ] > ( [ ] ) ;
574576 const checkpointIdRef = useRef < string | null > ( null ) ;
577+ const lastInputRef = useRef < string | null > ( null ) ;
575578
576579 const toggleFullscreen = useCallback ( async ( ) => {
577580 if ( ! appRef . current ) return ;
@@ -627,9 +630,9 @@ function ExcalidrawApp() {
627630 }
628631 } , [ displayMode , containerHeight ] ) ;
629632
630- // Mount editor when entering fullscreen
633+ // Mount editor when entering fullscreen or when host doesn't support fullscreen
631634 useEffect ( ( ) => {
632- if ( displayMode !== "fullscreen" ) {
635+ if ( displayMode !== "fullscreen" && canFullscreen ) {
633636 setEditorReady ( false ) ;
634637 setExcalidrawApi ( null ) ;
635638 setEditorSettled ( false ) ;
@@ -639,10 +642,10 @@ function ExcalidrawApp() {
639642 await document . fonts . ready ;
640643 setTimeout ( ( ) => setEditorReady ( true ) , 200 ) ;
641644 } ) ( ) ;
642- } , [ displayMode ] ) ;
645+ } , [ displayMode , canFullscreen ] ) ;
643646
644647 // After editor mounts: refresh text dimensions, then reveal
645- const mountEditor = displayMode === "fullscreen" && inputIsFinal && elements . length > 0 && editorReady ;
648+ const mountEditor = ( displayMode === "fullscreen" || ! canFullscreen ) && inputIsFinal && elements . length > 0 && editorReady ;
646649 useEffect ( ( ) => {
647650 if ( ! mountEditor || ! excalidrawApi ) return ;
648651 if ( editorSettled ) return ; // already revealed, don't redo
@@ -681,14 +684,25 @@ function ExcalidrawApp() {
681684 appRef . current = app ;
682685 _logFn = ( msg ) => { try { app . sendLog ( { level : "info" , logger : "FS" , data : msg } ) ; } catch { } } ;
683686
684- // Capture initial container dimensions
685- const initDims = app . getHostContext ( ) ?. containerDimensions as any ;
687+ // Capture initial container dimensions and host capabilities
688+ const initCtx = app . getHostContext ( ) as any ;
689+ const initDims = initCtx ?. containerDimensions ;
686690 if ( initDims ?. height ) setContainerHeight ( initDims . height ) ;
691+ if ( initDims ?. maxHeight ) setContainerMaxHeight ( initDims . maxHeight ) ;
692+ if ( initCtx ?. availableDisplayModes ) {
693+ setCanFullscreen ( initCtx . availableDisplayModes . includes ( "fullscreen" ) ) ;
694+ }
687695
688696 app . onhostcontextchanged = ( ctx : any ) => {
689697 if ( ctx . containerDimensions ?. height ) {
690698 setContainerHeight ( ctx . containerDimensions . height ) ;
691699 }
700+ if ( ctx . containerDimensions ?. maxHeight ) {
701+ setContainerMaxHeight ( ctx . containerDimensions . maxHeight ) ;
702+ }
703+ if ( ctx . availableDisplayModes ) {
704+ setCanFullscreen ( ctx . availableDisplayModes . includes ( "fullscreen" ) ) ;
705+ }
692706 if ( ctx . displayMode ) {
693707 fsLog ( `hostContextChanged: displayMode=${ ctx . displayMode } ` ) ;
694708 // Sync edited elements when host exits fullscreen
@@ -711,13 +725,17 @@ function ExcalidrawApp() {
711725
712726 app . ontoolinput = async ( input ) => {
713727 const args = ( input as any ) ?. arguments || input ;
728+ const sig = JSON . stringify ( args ) ;
729+ if ( lastInputRef . current === sig ) return ;
730+ lastInputRef . current = sig ;
714731 setInputIsFinal ( true ) ;
715732 setToolInput ( args ) ;
716733 } ;
717734
718735 app . ontoolresult = ( result : any ) => {
719736 const cpId = ( result . structuredContent as { checkpointId ?: string } ) ?. checkpointId ;
720737 if ( cpId ) {
738+ if ( cpId === checkpointIdRef . current ) return ;
721739 checkpointIdRef . current = cpId ;
722740 setCheckpointId ( cpId ) ;
723741 // Use checkpointId as localStorage key for persisting user edits
@@ -741,11 +759,11 @@ function ExcalidrawApp() {
741759 if ( ! app ) return < div className = "loading" > Connecting...</ div > ;
742760
743761 return (
744- < main className = { `main${ displayMode === "fullscreen" ? " fullscreen" : "" } ` } style = { displayMode === "fullscreen" && containerHeight ? { height : containerHeight } : undefined } >
745- { displayMode === "inline" && (
762+ < main className = { `main${ displayMode === "fullscreen" ? " fullscreen" : "" } ${ ! canFullscreen && mountEditor ? " inline-editor" : "" } ` } style = { displayMode === "fullscreen" && containerHeight ? { height : containerHeight } : ! canFullscreen && mountEditor ? { height : containerMaxHeight ?? 500 } : undefined } >
763+ { displayMode === "inline" && canFullscreen && (
746764 < div className = "toolbar" >
747765 < button
748- className = "fullscreen -btn"
766+ className = "toolbar -btn"
749767 onClick = { toggleFullscreen }
750768 title = "Enter fullscreen"
751769 >
0 commit comments