Compare commits

...
1 Commits
Author SHA1 Message Date
Miguel Palhas 766eabbcb6 fix(maestro): bind terminal touch scroll to .xterm
ci / web (push) Successful in 38s
ci / rust (push) Successful in 4m8s
ci / flake (push) Successful in 6m39s
The touch handlers sat on `.xterm-viewport`, but xterm appends the
absolutely-positioned viewport before the `position: relative` screen, so
`.xterm-screen` paints over it and takes every touch. The viewport is not an
ancestor of the screen, so the listeners never fired and mobile drags did
nothing. Moves them, and `touch-action: none`, to `.xterm`.
2026-09-01 13:10:18 +01:00
2 changed files with 12 additions and 8 deletions
+6 -4
View File
@@ -143,8 +143,10 @@ export function createAttachConnection(
// • alt screen with no mouse tracking → nothing to do; the app owns input. // • alt screen with no mouse tracking → nothing to do; the app owns input.
// `touch-action: none` (CSS) keeps the browser from cancelling the custom // `touch-action: none` (CSS) keeps the browser from cancelling the custom
// gesture stream; only the terminal surface opts out of native page panning. // gesture stream; only the terminal surface opts out of native page panning.
// Listeners MUST sit on `.xterm`, not `.xterm-viewport`: `.xterm-screen` is a
// later sibling of the viewport, so it paints over it and takes every touch.
{ {
const vp = el.querySelector(".xterm-viewport") as HTMLElement | null; const root = term.element as HTMLElement | undefined;
const screen = el.querySelector(".xterm-screen") as HTMLElement | null; const screen = el.querySelector(".xterm-screen") as HTMLElement | null;
const cellH = () => { const cellH = () => {
const core = (term as unknown as { const core = (term as unknown as {
@@ -152,11 +154,11 @@ export function createAttachConnection(
})._core; })._core;
return core?._renderService?.dimensions?.css?.cell?.height || 16; return core?._renderService?.dimensions?.css?.cell?.height || 16;
}; };
if (vp) { if (root) {
let lastY = 0; let lastY = 0;
let lastX = 0; let lastX = 0;
let remainder = 0; let remainder = 0;
vp.addEventListener( root.addEventListener(
"touchstart", "touchstart",
(e) => { (e) => {
if (e.touches.length !== 1) return; if (e.touches.length !== 1) return;
@@ -166,7 +168,7 @@ export function createAttachConnection(
}, },
{ passive: true }, { passive: true },
); );
vp.addEventListener( root.addEventListener(
"touchmove", "touchmove",
(e) => { (e) => {
if (e.touches.length !== 1) return; if (e.touches.length !== 1) return;
+6 -4
View File
@@ -1332,10 +1332,12 @@ input.leaf-rename:focus {
.attach-body .xterm .xterm-viewport { .attach-body .xterm .xterm-viewport {
overflow-y: auto; overflow-y: auto;
scrollbar-width: none; scrollbar-width: none;
/* Maestro drives scrollback from touchmove (see attach.ts). `pan-y` hands }
the gesture to the browser, which may cancel the event stream before the
terminal sees it; `none` keeps a drag inside the terminal under our /* Maestro drives scrollback from touchmove (see attach.ts), so the browser must
control while the rest of the page retains native scrolling. */ not claim the gesture. On `.xterm`, not the viewport: `.xterm-screen` paints
over the viewport and is what a finger lands on. */
.attach-body .xterm {
touch-action: none; touch-action: none;
} }