feat(mobile): native composer bar — UIKit keyboard tracking, quick keys, glass input

Closed
SA
3mo ago
+508-83

Stacked on #6342. First step of the fully-native input direction: a modules/composer Expo module that owns the input surface, replacing KeyboardAvoidingView + the RN quick-keys row on the terminal screen.

Why native

The Slack/Cursor input feel lives entirely on the native side of the RN boundary: keyboardLayoutGuide rides the keyboard's real animation curve (RN's KeyboardAvoidingView approximates it with a timing animation — the visible jank), and first-responder control means the keyboard actually appears (the WKWebView xterm textarea never reliably focused, #6342's known gap).

Design

  • ComposerView (UIKit ExpoView) mounts as a full-screen overlay; every touch outside the bar passes through via hitTest. The bar pins to self.keyboardLayoutGuide.topAnchor, so UIKit owns tracking end to end.
  • Props in, events out — no RN children. placeholder, autoFocus, quickKeys: [{id, label|symbol}] (SF Symbols); onSubmitText, onChangeText, onFocusChange, onQuickKey, onBarMetrics (occluded height, used by RN to inset content). The draft lives natively; RN only mirrors it.
  • Growing UITextView (1→~5 lines), send button appears with text, clears on submit.
  • Glass: UIGlassEffect on iOS 26, systemThickMaterialDark before — the pre-26 no-op gap the home widget has is designed out here.
  • Terminal screen: quick-key byte map + bracketed-paste framing for multiline submits stay in RN.

Verified on iOS 26.5 simulator (Maestro, full local stack, live claude PTY)

  • Bar renders (glass pill, placeholder, SF-symbol quick keys) in the bottom safe area.
  • Tap focuses the native field → keyboard appears with the bar riding it; terminal content resizes above via onBarMetrics.
  • Typed "hi there" via the soft keyboard, tapped send → claude received it (\r confirmed its trust prompt), field auto-cleared, session booted, and the OSC title updated the nav header live. Full native-input → PTY → render round trip.
  • Repo typecheck + lint clean.

Follow-ups

  • Keyboard dismiss affordance (the WebView isn't a scrollview, so no drag-to-dismiss surface yet).
  • Home NewChatWidget migration onto this module (chips row, voice dictation moving to native SFSpeechRecognizer) — next PR of the native-composer track.
  • Ref view-functions (focusInput/blurInput/clearText) are wired but have no call sites yet; exercise when the home widget migrates.

Summary by cubic

Introduces a native UIKit composer bar for iOS that replaces the RN input and quick-keys row on the Terminal screen. Smooth keyboard tracking, reliable focus, glass UI, and built-in quick keys.

  • New Features

    • Added @superset/composer Expo module with a native ComposerBar (keyboardLayoutGuide tracking, glass background, quick keys).
    • Terminal screen uses ComposerBar; removed KeyboardAvoidingView and the RN quick-keys row.
    • Emits occluded height to inset content; submit clears input; focus is first-responder native.
    • Props/events: placeholder, autoFocus, quickKeys; submit/change/focus/metrics. Methods: focus, blur, clear.
    • Multiline input is framed as bracketed paste before sending to the PTY.
  • Dependencies

    • Added iOS module with Composer.podspec; registered ComposerModule.
    • Wired module path in Metro and tsconfig (@superset/composer).