Skip to content

Commit 61a72de

Browse files
committed
fix(html): stabilize mobile keyboard viewport and background
1 parent 647d55a commit 61a72de

2 files changed

Lines changed: 76 additions & 3 deletions

File tree

html/src/components/terminal/xterm/index.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export class Xterm {
101101
private reconnect = true;
102102
private doReconnect = true;
103103
private closeOnDisconnect = false;
104+
private parent?: HTMLElement;
104105

105106
private writeFunc = (data: ArrayBuffer) => this.writeData(new Uint8Array(data));
106107

@@ -153,6 +154,7 @@ export class Xterm {
153154

154155
@bind
155156
public open(parent: HTMLElement) {
157+
this.parent = parent;
156158
this.terminal = new Terminal(this.options.termOptions);
157159
const { terminal, fitAddon, overlayAddon, clipboardAddon, webLinksAddon } = this;
158160
window.term = terminal as TtydTerminal;
@@ -166,9 +168,33 @@ export class Xterm {
166168
terminal.loadAddon(webLinksAddon);
167169

168170
terminal.open(parent);
171+
this.syncPageBackground();
172+
this.syncViewport();
169173
fitAddon.fit();
170174
}
171175

176+
@bind
177+
private syncPageBackground() {
178+
const themeBackground = this.terminal?.options.theme?.background;
179+
const color = typeof themeBackground === 'string' && themeBackground !== '' ? themeBackground : '#2b2b2b';
180+
document.documentElement.style.backgroundColor = color;
181+
document.body.style.backgroundColor = color;
182+
}
183+
184+
@bind
185+
private syncViewport() {
186+
if (!this.parent) return;
187+
const viewport = window.visualViewport;
188+
if (viewport) {
189+
const offsetTop = Math.max(0, Math.round(viewport.offsetTop));
190+
this.parent.style.height = `${Math.round(viewport.height)}px`;
191+
this.parent.style.top = `${offsetTop}px`;
192+
} else {
193+
this.parent.style.height = '';
194+
this.parent.style.top = '';
195+
}
196+
}
197+
172198
@bind
173199
private initListeners() {
174200
const { terminal, fitAddon, overlayAddon, register, sendData } = this;
@@ -199,7 +225,25 @@ export class Xterm {
199225
this.overlayAddon?.showOverlay('\u2702', 200);
200226
})
201227
);
202-
register(addEventListener(window, 'resize', () => fitAddon.fit()));
228+
register(
229+
addEventListener(window, 'resize', () => {
230+
this.syncViewport();
231+
fitAddon.fit();
232+
})
233+
);
234+
if (window.visualViewport) {
235+
register(
236+
addEventListener(window.visualViewport, 'resize', () => {
237+
this.syncViewport();
238+
fitAddon.fit();
239+
})
240+
);
241+
register(
242+
addEventListener(window.visualViewport, 'scroll', () => {
243+
this.syncViewport();
244+
})
245+
);
246+
}
203247
register(addEventListener(window, 'beforeunload', this.onWindowUnload));
204248
}
205249

@@ -466,6 +510,7 @@ export class Xterm {
466510
break;
467511
}
468512
}
513+
this.syncPageBackground();
469514
}
470515

471516
@bind

html/src/style/index.scss

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,43 @@ body {
44
min-height: 100%;
55
margin: 0;
66
overflow: hidden;
7+
overscroll-behavior: none;
8+
background-color: #2b2b2b;
9+
position: fixed;
10+
inset: 0;
11+
width: 100%;
712
}
813

914
#terminal-container {
10-
width: auto;
15+
position: fixed;
16+
top: 0;
17+
left: 0;
18+
right: 0;
19+
width: 100%;
1120
height: 100%;
12-
margin: 0 auto;
21+
margin: 0;
1322
padding: 0;
23+
overflow: hidden;
1424
.terminal {
1525
padding: 5px;
1626
height: calc(100% - 10px);
1727
}
1828
}
29+
30+
.xterm .xterm-viewport {
31+
overscroll-behavior-y: contain;
32+
-webkit-overflow-scrolling: touch;
33+
touch-action: pan-y;
34+
}
35+
36+
@media (hover: none) and (pointer: coarse) {
37+
.xterm .xterm-viewport {
38+
scrollbar-width: none;
39+
}
40+
41+
.xterm .xterm-viewport::-webkit-scrollbar {
42+
width: 0;
43+
height: 0;
44+
display: none;
45+
}
46+
}

0 commit comments

Comments
 (0)