@cplieger/web-terminal-ui 6.1.5 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/web-terminal-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Reference touch-first browser UI for @cplieger/web-terminal-engine: a composable kernel + feature modules (tabs, activity monitor, mobile toolbar, context menu, IME, predictive echo, viewport handling) and CSS. One createTerminal() call.",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"verify": "bash scripts/verify.sh"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@cplieger/web-terminal-engine": "^
|
|
43
|
+
"@cplieger/web-terminal-engine": "^5.0.3"
|
|
44
44
|
},
|
|
45
45
|
"overrides": {
|
|
46
46
|
"qs": "^6.15.2"
|
|
@@ -188,9 +188,6 @@ export function contextMenu(opts: ContextMenuOptions = {}): TerminalFeature {
|
|
|
188
188
|
clipboard.paste();
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
|
-
if (menu.childElementCount === 0) {
|
|
192
|
-
return; // nothing to offer
|
|
193
|
-
}
|
|
194
191
|
// Make visible (so it has measurable size), then place it within the
|
|
195
192
|
// visible viewport via the shared point-anchored positioner (clamp to the
|
|
196
193
|
// visual viewport; flip above the finger near the bottom edge).
|
|
@@ -244,7 +244,12 @@ async function createSessionHonouringRetry(
|
|
|
244
244
|
isTornDown: () => boolean,
|
|
245
245
|
): Promise<SessionInfo> {
|
|
246
246
|
const startedAt = Date.now();
|
|
247
|
-
|
|
247
|
+
// The elapsed reading of the last announcement, or null when nothing has been
|
|
248
|
+
// announced yet. NOT a 0 sentinel: elapsed is legitimately 0 when the server
|
|
249
|
+
// refuses inside the first millisecond (a host on the same machine), and a 0
|
|
250
|
+
// sentinel read that as "never spoken" and re-announced on the next refusal —
|
|
251
|
+
// the one thing the throttle below exists to prevent.
|
|
252
|
+
let lastAnnouncedAt: number | null = null;
|
|
248
253
|
for (;;) {
|
|
249
254
|
try {
|
|
250
255
|
return await api.create();
|
|
@@ -266,7 +271,7 @@ async function createSessionHonouringRetry(
|
|
|
266
271
|
// only said "not yet" -- and the first announcement fires before any retry
|
|
267
272
|
// has happened at all, so a user two seconds into a boot was told
|
|
268
273
|
// "retrying" about a request that had been made exactly once.
|
|
269
|
-
if (lastAnnouncedAt ===
|
|
274
|
+
if (lastAnnouncedAt === null || elapsed - lastAnnouncedAt >= CREATE_RETRY_REANNOUNCE_MS) {
|
|
270
275
|
lastAnnouncedAt = elapsed;
|
|
271
276
|
const reason = err.serverMessage ?? "Server is not ready yet";
|
|
272
277
|
ctx.toast(`${reason}; waiting…`, 8000);
|
package/src/kernel/kernel.ts
CHANGED
|
@@ -601,7 +601,13 @@ function buildTerminal(
|
|
|
601
601
|
|
|
602
602
|
connection.init({
|
|
603
603
|
computeSize: render.computeSize,
|
|
604
|
-
getHaveThrough
|
|
604
|
+
// getHaveThrough is deliberately NOT supplied. The engine defaults it to its
|
|
605
|
+
// own renderer (engine >= 5.0.3), which is the only party that knows which
|
|
606
|
+
// store is currently bound and which of its rows the server has confirmed.
|
|
607
|
+
// Supplying it from here is what claimed rows the application had merely
|
|
608
|
+
// DRAWN — `render.getHighestIndex` is the window's bottom row — and left a
|
|
609
|
+
// frozen copy of the composer parked in scrollback on almost every reattach.
|
|
610
|
+
// An explicit member wins over the default, so re-adding one reopens that.
|
|
605
611
|
// --- Demand-paged scrollback (engine docs/paged-scrollback.md §4-5) ---
|
|
606
612
|
// The transport is store-blind and viewport-blind by design, so every one of
|
|
607
613
|
// these forwards a decision only the renderer can make. Without them the
|
|
@@ -784,29 +790,29 @@ function buildTerminal(
|
|
|
784
790
|
);
|
|
785
791
|
|
|
786
792
|
/**
|
|
787
|
-
* Applies
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
* coming
|
|
793
|
+
* Applies a `mapKeyboardEvent` result. BOTH keydown paths — the focused textarea
|
|
794
|
+
* below, and the document-level type-to-focus fallback in the focus-strategy
|
|
795
|
+
* section — handle every arm identically, including "ignore": the textarea lets
|
|
796
|
+
* its own `input` event deliver the character, and the fallback has already
|
|
797
|
+
* resolved that case before it gets here, computing the typed character itself
|
|
798
|
+
* because no `input` event is coming for a key that targeted the body.
|
|
793
799
|
*
|
|
794
|
-
* Switching over the whole `KeyboardResult` union in one place is what keeps
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
800
|
+
* Switching over the whole `KeyboardResult` union in one place is what keeps the
|
|
801
|
+
* two paths from drifting — handling only "send" in the fallback silently dropped
|
|
802
|
+
* Shift+PageUp, which is exactly what a reader who just selected some scrollback
|
|
803
|
+
* presses next.
|
|
798
804
|
*/
|
|
799
|
-
function applyMappedKey(ev: KeyboardEvent, result: keyboard.KeyboardResult):
|
|
805
|
+
function applyMappedKey(ev: KeyboardEvent, result: keyboard.KeyboardResult): void {
|
|
800
806
|
switch (result.kind) {
|
|
801
807
|
case "send":
|
|
802
808
|
ev.preventDefault();
|
|
803
809
|
sendText(result.bytes);
|
|
804
|
-
return
|
|
810
|
+
return;
|
|
805
811
|
case "scroll-up": {
|
|
806
812
|
ev.preventDefault();
|
|
807
813
|
const h = termWrap.clientHeight;
|
|
808
814
|
termWrap.scrollTop = Math.max(0, termWrap.scrollTop - h);
|
|
809
|
-
return
|
|
815
|
+
return;
|
|
810
816
|
}
|
|
811
817
|
case "scroll-down": {
|
|
812
818
|
ev.preventDefault();
|
|
@@ -817,10 +823,10 @@ function buildTerminal(
|
|
|
817
823
|
// reasoning as the engine's bottom writes.
|
|
818
824
|
const max = Math.max(0, termWrap.scrollHeight - h);
|
|
819
825
|
termWrap.scrollTop = Math.min(max, termWrap.scrollTop + h);
|
|
820
|
-
return
|
|
826
|
+
return;
|
|
821
827
|
}
|
|
822
828
|
case "ignore":
|
|
823
|
-
return
|
|
829
|
+
return;
|
|
824
830
|
}
|
|
825
831
|
}
|
|
826
832
|
|
|
@@ -836,9 +842,9 @@ function buildTerminal(
|
|
|
836
842
|
return;
|
|
837
843
|
}
|
|
838
844
|
}
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
//
|
|
845
|
+
// Nothing more is needed for an "ignore": the `input` listener above delivers
|
|
846
|
+
// the character, which is also how IME and dead-key composition output
|
|
847
|
+
// reaches the terminal.
|
|
842
848
|
applyMappedKey(ev, mapKeyboardEvent(ev, modes));
|
|
843
849
|
},
|
|
844
850
|
{ signal },
|