From c65eff50bc42e8ae061b0ecb600df4719271d4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Sat, 19 Sep 2026 06:02:10 +0000 Subject: [PATCH] fix(mobile): keep PR Review URL placeholder on one line Explorer finding: pr-review: The URL field's placeholder wraps and its second line is cut off by the field's bottom edge. The user-agent explorer found this while using the app like a user. One finding per item; the explorer never edits product code. Flow: pr-review Found on revision: fd04ca1ef Repro: 1. set this state first: account e2e-mobile-cloud-android@example.com, $10 credits, 3 Code Reviewer pull requests, one top-level busy session (ses_f488ff9c9ffefhXjlZMDy7Ix8y), display 720x1600, day mode, font 1.0, portrait, **event-service down**. 2. open the app on emulator-5554 3. reach the screen the capture names (pr-review) 4. the capture shows the defect named below Observed: The URL field's placeholder wraps and its second line is cut off by the field's bottom edge. Expected: the screen renders without this defect Evidence (from the device run): - ~/.local/share/kwf/findings/explorer-pr-review-the-url-field-s-placeholder-wraps-and-fce9b5ce/pr-review.png Production record (automatic, 2026-09-19): ## Production record for `ses_f488ff9c9ffefhXjlZMDy7Ix8y` ### Axiom, last 72 h No line carries this term in: `vercel`, `cloudflare-logpush`, `supabase-production`. ### The session row, read replica No row in `cli_sessions_v2` carries `ses_f488ff9c9ffefhXjlZMDy7Ix8y`. ### Log archives, R2 `kilocode-sessions` NOT READ: R2 keys are indexed by the agent id, not the session id; take the agent_* from the worker logs above and query that. ### Sentry, last 72h No Sentry issue ca --- .../pr-review/pr-review-entry-screen.test.ts | 15 +++++++++++++++ .../pr-review/pr-review-entry-screen.tsx | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts b/apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts index e589d7b1ee..7c2e33c644 100644 --- a/apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts +++ b/apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts @@ -125,6 +125,21 @@ describe('provider-neutral URL field', () => { expect(mocks.push).not.toHaveBeenCalled(); }); + it('keeps the one-line field from wrapping and clipping its placeholder', async () => { + const tree = await renderLoaded(); + const input = propsOf(find(tree, 'TextInput', () => true)); + // The field is one line tall, so Android must not wrap the hint onto a + // second line: the hint's second line was drawn below the field's own + // bounds and clipped at its bottom edge (explorer capture). numberOfLines + // caps the native hint layout at one line instead of wrapping it. + expect(input.numberOfLines).toBe(1); + expect(input.multiline).toBeFalsy(); + // Height comes from min-h-* (see apps/mobile/AGENTS.md), never py-*: + // vertical padding draws the single-line text below the middle. + expect(String(input.className)).toContain('min-h-14'); + expect(String(input.className)).not.toContain('py-3'); + }); + it('shows the clear control only once the field has text', async () => { const before = await renderLoaded(); expect( diff --git a/apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx b/apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx index cf177f2d42..4495f692f7 100644 --- a/apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx +++ b/apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx @@ -275,9 +275,16 @@ export function PrReviewEntryScreen() { inputValueRef.current = value; setHasInput(value.length > 0); }} + // A one-line field: without numberOfLines the native hint wraps + // onto a second line the field's bounds then clip at the bottom + // edge (Android explorer capture). The cap keeps the hint on one + // line; the label above already states what the field takes. + numberOfLines={1} // leading-[normal] so no lineHeight reaches the style: an explicit lineHeight // makes iOS draw the placeholder lower than the typed text (see AGENTS.md). - className="min-w-0 flex-1 bg-transparent py-3 pl-3 pr-1 text-base text-foreground leading-[normal]" + // min-h-14 (not py-3) sizes the field: vertical padding draws the + // single-line text below the middle (see AGENTS.md). + className="min-h-14 min-w-0 flex-1 bg-transparent pl-3 pr-1 text-base text-foreground leading-[normal]" accessibilityLabel={t('prReview.entry.urlAccessibility')} returnKeyType="go" onSubmitEditing={handleSubmit}