@cplieger/web-terminal-ui 2.1.0 → 2.1.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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/src/mount.ts +19 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/web-terminal-ui",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "type": "module",
5
5
  "description": "Reference touch-first browser UI for @cplieger/web-terminal-engine: textarea input model, mobile key toolbar, context menu, IME, predictive echo, viewport/keyboard-inset handling, and CSS. One mount() call.",
6
6
  "license": "GPL-3.0-or-later",
@@ -31,8 +31,8 @@
31
31
  "fast-check": "4.8.0",
32
32
  "happy-dom": "20.10.6",
33
33
  "html-validate": "11.5.3",
34
- "knip": "6.22.0",
35
- "prettier": "3.9.0",
34
+ "knip": "6.23.0",
35
+ "prettier": "3.9.1",
36
36
  "stylelint": "17.14.0",
37
37
  "stylelint-config-standard": "40.0.0",
38
38
  "typescript": "6.0.3",
package/src/mount.ts CHANGED
@@ -645,6 +645,25 @@ export function mount(root: HTMLElement, opts: MountOptions = {}): TerminalUI {
645
645
  },
646
646
  { passive: true },
647
647
  );
648
+ // After a touch tap, iOS/WebKit dispatches a synthetic `mousedown` (following
649
+ // the `pointerup` above). Its default action moves focus to the nearest
650
+ // focusable ancestor of the tap point — but the input-model contract keeps
651
+ // `.term-output` and `.term` deliberately non-focusable (display-only) and the
652
+ // hidden textarea is `pointer-events: none`, so the tap never lands on a
653
+ // focusable node. With nothing focusable under the tap, that default blurs the
654
+ // textarea we just focused in `pointerup`, so iOS immediately dismisses the
655
+ // soft keyboard the tap had only just opened — the "keyboard flashes open then
656
+ // instantly closes" symptom on touch. Cancelling the synthetic mousedown's
657
+ // default keeps focus on the textarea, so the keyboard stays up. This is the
658
+ // xterm.js focus-preservation pattern, scoped to touch: a real mouse mousedown
659
+ // must keep its default so desktop drag-to-select text still works, and iOS
660
+ // text selection is long-press-driven (not this tap mousedown), so it is
661
+ // unaffected. Not passive — preventDefault must take effect.
662
+ termWrap.addEventListener("mousedown", (e) => {
663
+ if (lastPointerType === "touch") {
664
+ e.preventDefault();
665
+ }
666
+ });
648
667
  termWrap.addEventListener("click", (e) => {
649
668
  // Terminal links: URLs rendered by the engine are wrapped in
650
669
  // <a class="term-link" target="_blank" rel="noopener noreferrer">. The