@cplieger/web-terminal-ui 7.0.0 → 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": "7.0.0",
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",
@@ -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
- let lastAnnouncedAt = 0;
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 === 0 || elapsed - lastAnnouncedAt >= CREATE_RETRY_REANNOUNCE_MS) {
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);
@@ -790,29 +790,29 @@ function buildTerminal(
790
790
  );
791
791
 
792
792
  /**
793
- * Applies the part of a `mapKeyboardEvent` result that BOTH keydown paths (the
794
- * focused textarea below, and the document-level type-to-focus fallback in the
795
- * focus-strategy section) handle identically. Returns false only for "ignore",
796
- * the one arm the two callers resolve differently: the textarea lets its own
797
- * `input` event deliver the character, while the fallback has no `input` event
798
- * coming and must send the character itself.
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.
799
799
  *
800
- * Switching over the whole `KeyboardResult` union in one place is what keeps
801
- * the two paths from drifting — handling only "send" in the fallback silently
802
- * dropped Shift+PageUp, which is exactly what a reader who just selected some
803
- * scrollback presses next.
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.
804
804
  */
805
- function applyMappedKey(ev: KeyboardEvent, result: keyboard.KeyboardResult): boolean {
805
+ function applyMappedKey(ev: KeyboardEvent, result: keyboard.KeyboardResult): void {
806
806
  switch (result.kind) {
807
807
  case "send":
808
808
  ev.preventDefault();
809
809
  sendText(result.bytes);
810
- return true;
810
+ return;
811
811
  case "scroll-up": {
812
812
  ev.preventDefault();
813
813
  const h = termWrap.clientHeight;
814
814
  termWrap.scrollTop = Math.max(0, termWrap.scrollTop - h);
815
- return true;
815
+ return;
816
816
  }
817
817
  case "scroll-down": {
818
818
  ev.preventDefault();
@@ -823,10 +823,10 @@ function buildTerminal(
823
823
  // reasoning as the engine's bottom writes.
824
824
  const max = Math.max(0, termWrap.scrollHeight - h);
825
825
  termWrap.scrollTop = Math.min(max, termWrap.scrollTop + h);
826
- return true;
826
+ return;
827
827
  }
828
828
  case "ignore":
829
- return false;
829
+ return;
830
830
  }
831
831
  }
832
832
 
@@ -842,9 +842,9 @@ function buildTerminal(
842
842
  return;
843
843
  }
844
844
  }
845
- // A false return ("ignore") needs nothing here: the `input` listener above
846
- // delivers the character, which is also how IME and dead-key composition
847
- // output reaches the terminal.
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.
848
848
  applyMappedKey(ev, mapKeyboardEvent(ev, modes));
849
849
  },
850
850
  { signal },