@cplieger/web-terminal-ui 8.6.0-dev.10 → 8.6.0-dev.12

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": "8.6.0-dev.10",
3
+ "version": "8.6.0-dev.12",
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",
@@ -51,18 +51,18 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@eslint/js": "10.0.1",
54
- "@stryker-mutator/core": "10.0.0",
55
- "@stryker-mutator/typescript-checker": "10.0.0",
56
- "@stryker-mutator/vitest-runner": "10.0.0",
57
- "@types/node": "26.6.5",
54
+ "@stryker-mutator/core": "10.1.1",
55
+ "@stryker-mutator/typescript-checker": "10.1.1",
56
+ "@stryker-mutator/vitest-runner": "10.1.1",
57
+ "@types/node": "26.6.6",
58
58
  "@typescript/native": "npm:typescript@7.0.2",
59
59
  "@vitest/browser": "5.0.5",
60
60
  "@vitest/browser-playwright": "5.0.5",
61
61
  "@vitest/coverage-v8": "5.0.5",
62
- "eslint": "10.12.0",
62
+ "eslint": "10.13.0",
63
63
  "fast-check": "4.10.2",
64
- "html-validate": "11.16.2",
65
- "knip": "6.41.0",
64
+ "html-validate": "11.17.0",
65
+ "knip": "6.43.0",
66
66
  "playwright": "1.64.1",
67
67
  "prettier": "3.9.10",
68
68
  "stylelint": "17.16.0",
@@ -1,5 +1,6 @@
1
1
  import { windowOf } from "../kernel/realm.js";
2
2
  import { selectionTextWithin } from "../kernel/selection.js";
3
+ import { isShortcutLetter } from "../kernel/shortcut-letter.js";
3
4
  import type { TerminalFeature } from "../kernel/types.js";
4
5
 
5
6
  /** The value a peer reads through `ctx.use(clipboard())`. Both members are
@@ -62,11 +63,11 @@ export function clipboard(): TerminalFeature<ClipboardApi> {
62
63
  // Consuming plain Ctrl+V without preventDefault stops the kernel mapping
63
64
  // it to \x16 while the native paste still flows into the textarea, so no
64
65
  // clipboard read and no Firefox clipboard-read popup.
65
- if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.code === "KeyV") {
66
+ if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && isShortcutLetter(ev, "v")) {
66
67
  return true;
67
68
  }
68
69
  if (ev.ctrlKey && ev.shiftKey && !ev.altKey && !ev.metaKey) {
69
- if (ev.code === "KeyC") {
70
+ if (isShortcutLetter(ev, "c")) {
70
71
  const sel = selectionTextWithin(surface);
71
72
  if (sel !== "") {
72
73
  copy(sel);
@@ -74,7 +75,7 @@ export function clipboard(): TerminalFeature<ClipboardApi> {
74
75
  ev.preventDefault();
75
76
  return true;
76
77
  }
77
- if (ev.code === "KeyV") {
78
+ if (isShortcutLetter(ev, "v")) {
78
79
  paste();
79
80
  ev.preventDefault();
80
81
  return true;
@@ -14,6 +14,7 @@ import { createRegions } from "./regions.js";
14
14
  import { createAnnouncer, createPaneTablist, type PaneTablist } from "./a11y.js";
15
15
  import { createConnState } from "./conn-state.js";
16
16
  import { selectionTextWithin } from "./selection.js";
17
+ import { isShortcutLetter } from "./shortcut-letter.js";
17
18
  import { primaryPointerFine } from "./keyboard-presence.js";
18
19
  import { windowOf } from "./realm.js";
19
20
  import {
@@ -77,16 +78,12 @@ function typedChar(ev: KeyboardEvent): string | null {
77
78
  return first !== undefined && String.fromCodePoint(first) === ev.key ? ev.key : null;
78
79
  }
79
80
 
80
- /** Ctrl+C (Shift allowed) or Ctrl+Insert: the chords that copy a selection. A
81
- * non-Latin layout's C is its physical KeyC; a Latin layout's is `key`. */
81
+ /** Ctrl+C (Shift allowed) or Ctrl+Insert: the chords that copy a selection. */
82
82
  function isCopyChord(ev: KeyboardEvent): boolean {
83
83
  if (!ev.ctrlKey || ev.altKey || ev.metaKey) {
84
84
  return false;
85
85
  }
86
- if (ev.key === "Insert" || ev.key === "c" || ev.key === "C") {
87
- return true;
88
- }
89
- return ev.code === "KeyC" && !/^[a-z]$/i.test(ev.key);
86
+ return ev.key === "Insert" || isShortcutLetter(ev, "c");
90
87
  }
91
88
 
92
89
  /** iOS sends U+00A0 where a space was typed; shared by every send path so one
@@ -0,0 +1,9 @@
1
+ /** True when `ev` is the shortcut letter `letter` (lowercase a-z): its `key`, either
2
+ * case, when the key types an ASCII letter (Dvorak's C is on KeyI), else its physical
3
+ * `Key<letter>` (Russian С on KeyC, or a non-ASCII Latin letter such as é). */
4
+ export function isShortcutLetter(ev: KeyboardEvent, letter: string): boolean {
5
+ if (ev.key.toLowerCase() === letter) {
6
+ return true;
7
+ }
8
+ return ev.code === `Key${letter.toUpperCase()}` && !/^[a-z]$/i.test(ev.key);
9
+ }