fix: xterm.js mobile touch scrolling via viewport CSS and stopPropagation
- Add full mobile viewport CSS: overflow-y scroll, -webkit-overflow-scrolling touch, overscroll-behavior-y contain, translate3d hardware accel, scroll-behavior smooth, touch-action pan-y - After term.open(), find .xterm-viewport and add passive touch listeners that call stopPropagation() (not preventDefault) — this lets the browser handle native touch scrolling while preventing xterm.js internal handlers from interfering - Based on xterm.js known issue #5489 and SCROLLING_FIX.md approach
This commit is contained in:
@@ -311,6 +311,37 @@ export const TerminalComponent = React.forwardRef<TerminalRef, TerminalProps>(
|
||||
// Open xterm first (must happen before fit)
|
||||
term.open(container);
|
||||
term.focus();
|
||||
|
||||
// Mobile: allow native touch scroll on xterm viewport.
|
||||
// xterm.js 5.x+ uses SmoothScrollableElement which can block native
|
||||
// touch scrolling. We add passive touch listeners that call
|
||||
// stopPropagation (not preventDefault) so the browser handles the
|
||||
// gesture natively while xterm.js internal handlers don't fire.
|
||||
let touchCleanup: (() => void) | undefined;
|
||||
if (isMobile) {
|
||||
const viewport = container.querySelector(
|
||||
".xterm-viewport",
|
||||
) as HTMLElement | null;
|
||||
if (viewport) {
|
||||
const onTouchStart = (e: TouchEvent) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
const onTouchMove = (e: TouchEvent) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
viewport.addEventListener("touchstart", onTouchStart, {
|
||||
passive: true,
|
||||
});
|
||||
viewport.addEventListener("touchmove", onTouchMove, {
|
||||
passive: true,
|
||||
});
|
||||
touchCleanup = () => {
|
||||
viewport.removeEventListener("touchstart", onTouchStart);
|
||||
viewport.removeEventListener("touchmove", onTouchMove);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const ws = connectWebSocket();
|
||||
|
||||
// Initial fit after layout settles (terminal must be opened first)
|
||||
@@ -429,8 +460,6 @@ export const TerminalComponent = React.forwardRef<TerminalRef, TerminalProps>(
|
||||
};
|
||||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||||
|
||||
|
||||
|
||||
return () => {
|
||||
isUnmountingRef.current = true;
|
||||
clearTimeout(resizeTimeout);
|
||||
@@ -442,6 +471,7 @@ export const TerminalComponent = React.forwardRef<TerminalRef, TerminalProps>(
|
||||
"visibilitychange",
|
||||
handleVisibilityChange,
|
||||
);
|
||||
if (touchCleanup) touchCleanup();
|
||||
if (ws) {
|
||||
ws.close(1000, "Component unmounting");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user