fix Android preview not rerendering when exiting fullscreen code editor

Hunter
Wednesday, December 24th, 2025 at 10:05 PM

main.js+28-44

main.js
426  
427  		// If we are on mobile and the keyboard mode is active,
428  		// exit immediately. Do not wait for visualViewport resize.
    -		if (isMobileDevice() && document.body.classList.contains('mobile-keyboard-open')) {
    -
    -			// 1. Hide editor immediately to prevent the "stutter/jump" visual
    -			editorPane.style.opacity = '0';
    -
    -			// 2. Remove the class to trigger layout engine (100% -> 50% height)
    -			document.body.classList.remove('mobile-keyboard-open');
    -
    -			// 3. Wait for layout to settle, then restore scroll and opacity
    -			requestAnimationFrame(() => requestAnimationFrame(() => {
    -				if (editorView) {
    -					// Scroll cursor into view in the new 50% layout
    -					const pos = editorView.state.selection.main.head;
    -					const lineBlock = editorView.lineBlockAt(pos);
    -					const targetScroll = lineBlock.top - (editorView.dom.clientHeight / 2);
    -					editorView.scrollDOM.scrollTop = Math.max(0, targetScroll);
    -				}
    -				// Reveal the editor
    -				editorPane.style.opacity = '';
    -
    -				// Update preview with any changes made while keyboard was open
    -				updatePreview();
    -			}));
429 +		if (isMobileDevice()) {
430 +			exitMobileKeyboardMode();
431  		}
432  	});
433  

451  let initialViewportHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;
452  let isEditorFocused = false;
453  
454 +// Handle transition from fullscreen keyboard mode back to split view
455 +function exitMobileKeyboardMode() {
456 +	if (!document.body.classList.contains('mobile-keyboard-open')) return;
457 +
458 +	// Hide editor immediately to prevent visual stutter/jump
459 +	editorPane.style.opacity = '0';
460 +	document.body.classList.remove('mobile-keyboard-open');
461 +
462 +	// Wait for layout to settle, then restore scroll and opacity
463 +	requestAnimationFrame(() => requestAnimationFrame(() => {
464 +		if (editorView) {
465 +			// Scroll cursor into view in the new 50% layout
466 +			const pos = editorView.state.selection.main.head;
467 +			const lineBlock = editorView.lineBlockAt(pos);
468 +			const targetScroll = lineBlock.top - (editorView.dom.clientHeight / 2);
469 +			editorView.scrollDOM.scrollTop = Math.max(0, targetScroll);
470 +		}
471 +		editorPane.style.opacity = '';
472 +
473 +		// Update preview with any changes made while keyboard was open
474 +		updatePreview();
475 +	}));
476 +}
477 +
478  function updateViewportVariables() {
479  	const vv = window.visualViewport;
480  	if (vv) {

495  	if (isKeyboardOpen && isEditorFocused) {
496  		document.body.classList.add('mobile-keyboard-open');
497  	} else if (!isKeyboardOpen) {
    -		// Check if the class is still there (it might have been removed by blur already)
    -		const wasKeyboardOpen = document.body.classList.contains('mobile-keyboard-open');
    -
    -		if (wasKeyboardOpen) {
    -			// This is a fallback in case blur didn't catch it
    -			// (e.g. if the keyboard was dismissed via a gesture that didn't blur immediately)
    -			if (editorView) {
    -				const pos = editorView.state.selection.main.head;
    -				editorPane.style.opacity = '0';
    -				document.body.classList.remove('mobile-keyboard-open');
    -
    -				requestAnimationFrame(() => requestAnimationFrame(() => {
    -					const lineBlock = editorView.lineBlockAt(pos);
    -					const targetScroll = lineBlock.top - (editorView.dom.clientHeight / 2);
    -					editorView.scrollDOM.scrollTop = Math.max(0, targetScroll);
    -					editorPane.style.opacity = '';
    -				}));
    -			} else {
    -				document.body.classList.remove('mobile-keyboard-open');
    -			}
    -		}
498 +		// Fallback for keyboard dismissal that doesn't trigger blur (e.g. Android)
499 +		exitMobileKeyboardMode();
500  	}
501  }
502