fix(mobile): respect prose direction in chat and composer#23587

open5
main
GitHub fork: fix/mobile-bidi-text
opened7d agobyHhaithamassoli44
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

Mobile still resolves mixed prose from its first letter, even after #22777 fixed web and desktop. In StrictMode: يعيد العرض مرتين في التطوير, the English prefix makes the Arabic paragraph LTR. Inline fetch() reads as ()fetch, and RTL quote borders stay on the left. The same failure is reproducible in Hebrew.

Change

Use #22777's word-majority rule in the shared native Markdown renderer and the native chat/new-thread composers. Ties follow the first word; code and chips do not vote.

  • The pinned Enriched renderer gets an opt-in word-majority mode for iOS and Android. Lists and quotes share their block's direction; table cells resolve independently. Inline and fenced rendered code stay LTR.
  • Native composer direction is presentation metadata. Source text, UTF-16 selection offsets, chips, marked text and undo handling stay on their existing paths.
  • Tagged display controls are removed during plain-text, HTML, Markdown and custom-action export. Authored bidi marks are preserved.
  • Explicit table alignment remains physical left/right, independently of cell direction. Table column order keeps its existing behavior.

Scope and approval

Native follow-up to merged #22777 and the RTL rendering problem in #13622. The current native integration gap was also documented in the #16839 preflight. This uses the word policy already merged for web rather than introducing another direction heuristic.

The shared renderer covers user/assistant messages, review/PR Markdown and Markdown file previews. Composer changes cover chat and new-thread drafts. Provider adapters, server contracts and connection modes carry the same source text.

Verification

Rebuilt and verified matching native development clients on iPhone 18 Pro / iOS 27.0 and an Android 16 / API 36 emulator using node scripts/mobile-native-client.ts ensure ... and a final check on each platform.

Matched captures show English-led Arabic/Hebrew headings and paragraphs resolving RTL, inline fetch() retaining its order, quote borders on the right, and English/fenced code remaining LTR. The recordings exercise typing and a transition from an Arabic paragraph to an English paragraph. On Android, selected rich text containing inline code was copied and pasted into the composer; source prose/code remained intact without synthesized bidi controls.

  • vp run check:changed passed: format, lint, knip and typecheck of the 32 impacted packages. The dependency patch/lockfile expand this command's impact automatically.
  • bash apps/mobile/modules/t3-composer-editor/tests/check-text-direction.sh passed 15 word-vote cases, 12 documents, and UTF-16/trailing-line checks.
  • From apps/mobile/android: ./gradlew :t3-composer-editor:testDebugUnitTest --tests expo.modules.t3composereditor.ComposerTextDirectionTest :react-native-enriched-markdown:testDebugUnitTest --tests com.swmansion.enriched.markdown.utils.text.view.DirectionClipboardTest passed 12 tests: 5 composer and 7 renderer/clipboard cases. These include actual Android span/layout APIs, multiline code extraction, authored marks, HTML, explicit table alignment and preservation of RTL-locale column order.
  • Objective-C word-direction/AST/clipboard self-checks passed 11 direction cases plus block inheritance and independent tables. Focused source harnesses reproduced the export/alignment review bugs before their fixes and passed afterward. Added iOS XCTest regressions were syntax checked; a full XCTest target was not executed.
  • Targeted SwiftLint, ktlint and detekt passed for the changed composer sources/tests. The dependency patch dry-applies to the exact current archive; all 43 patched files match the verified tree.

Matched native captures

Both sides use the same isolated stopped-conversation fixtures with synthetic Arabic/Hebrew text. These verify client rendering, not a live provider response. Before uses native code from 8d3b061121fe; after uses this branch's rebuilt clients. PR-only assets are hosted on the fork release and are not committed.

Typing recordings: iOS (31 seconds) · Android (13 seconds).

Limits

The Android plaintext composer receives isolated paragraph buffers: it excludes inline code from word voting, but does not isolate inline-code runs, resolve fence bodies from the whole document, or inherit direction for neutral-only lines. Rendered Markdown uses its AST for code and block direction. Scheduled-task prompts and review-comment inputs keep their existing native text-input behavior. Physical devices, hardware-keyboard editing, IME composition/cancellation and undo/redo were not checked.

Implemented with GPT-6.1 Sol using the Codex harness in T3 Code.

Checks

5 successful · 1 skipped
All checks passed
0702e1c

Added 2 commits

  • fix(mobile): preserve table order in RTL locales1da551a
  • fix(mobile): respect prose direction in chat and composer9adee76
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This PR introduces broad Android/iOS Markdown rendering and composer direction behavior, activates a 1,665-line production dependency patch, and changes the mobile Markdown component’s effective direction default. The resulting cross-platform regression surface is substantially larger than a self-contained bug fix.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

Warning

Review limit reached

Only developers with an assigned seat can use this organization's usage-based review budget, and seats here are assigned manually. Ask an admin to assign a seat, or change the review continuation mode in Billing.

Next included review available in 31 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between 7c7db8ca0be7bab8e8018b169201e43715556490 and 0702e1c134467d5e1aaf3e396821f4c5ec970583.

External image Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
External image Files selected for processing: 10
  • apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/ComposerTextDirection.kt
  • apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/T3ComposerEditorView.kt
  • apps/mobile/modules/t3-composer-editor/android/src/test/java/expo/modules/t3composereditor/ComposerTextDirectionTest.kt
  • apps/mobile/modules/t3-composer-editor/ios/ComposerTextDirection.swift
  • apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift
  • apps/mobile/modules/t3-composer-editor/tests/ComposerTextDirectionCheck.swift
  • apps/mobile/modules/t3-composer-editor/tests/check-text-direction.sh
  • apps/mobile/src/native/EnrichedMarkdownText.tsx
  • patches/react-native-enriched-markdown@1.2.0-t3.16.patch
  • pnpm-workspace.yaml

No actionable comments were generated in the recent review.

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 8d3b061121fe65669d5d43d011b48cd3027a4108 and 1da551afed232e41072b4dc0d48556a6611ece34.

⛔ Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 10
  • apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/ComposerTextDirection.kt
  • apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/T3ComposerEditorView.kt
  • apps/mobile/modules/t3-composer-editor/android/src/test/java/expo/modules/t3composereditor/ComposerTextDirectionTest.kt
  • apps/mobile/modules/t3-composer-editor/ios/ComposerTextDirection.swift
  • apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift
  • apps/mobile/modules/t3-composer-editor/tests/ComposerTextDirectionCheck.swift
  • apps/mobile/modules/t3-composer-editor/tests/check-text-direction.sh
  • apps/mobile/src/native/EnrichedMarkdownText.tsx
  • patches/react-native-enriched-markdown@1.2.0-t3.15.patch
  • pnpm-workspace.yaml

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

The mobile composer now detects and applies paragraph direction on Android and iOS. The enriched Markdown component enables word-majority direction, which the patched native renderers use for Markdown blocks, tables, code, and output cleanup.

Changes: Mobile word-majority direction

Layer / File(s)Summary
Composer paragraph direction
apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/ComposerTextDirection.kt, apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/T3ComposerEditorView.kt, apps/mobile/modules/t3-composer-editor/android/src/test/java/expo/modules/t3composereditor/ComposerTextDirectionTest.kt, apps/mobile/modules/t3-composer-editor/ios/ComposerTextDirection.swift, apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift, apps/mobile/modules/t3-composer-editor/tests/*
Android and iOS classify paragraph direction by the first letter in each word. The editor applies direction to paragraphs and typing attributes, while code ranges remain left-to-right. Tests check direction votes, code handling, and UTF-16 offsets.
Markdown mode and direction annotation
apps/mobile/src/native/EnrichedMarkdownText.tsx, patches/react-native-enriched-markdown@1.2.0-t3.15.patch, pnpm-workspace.yaml
The mobile component sets writingDirection to word-majority. The patch adds the mode to native prop handling, annotates Markdown structures for rendering and measurement, and updates the TypeScript prop type.
Native direction-aware rendering
patches/react-native-enriched-markdown@1.2.0-t3.15.patch
Android and iOS apply direction metadata to paragraphs, code, blockquotes, and tables. The renderers add marked controls for code direction and handle direction in link pills.
Generated direction-control cleanup
patches/react-native-enriched-markdown@1.2.0-t3.15.patch
Markdown, HTML, clipboard, and RTF output omit generated direction controls. Added tests cover cleanup, authored directional marks, and table alignment.

Priority: External image Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Bug fix

Sequence Diagram(s)

mermaid
1sequenceDiagram
2 participant MobileEnrichedMarkdownText
3 participant EnrichedMarkdownText
4 participant wordMajorityAST
5 participant NativeRenderer
6 MobileEnrichedMarkdownText->>EnrichedMarkdownText: Set writingDirection to word-majority
7 EnrichedMarkdownText->>wordMajorityAST: Annotate parsed Markdown
8 wordMajorityAST->>NativeRenderer: Provide direction metadata

Suggested reviewers: juliusmarminge

Merge Risk: External image Minimal · up to 1da55

This change adds word-majority text direction to mobile Markdown rendering and the composers. No concrete merge-blocking defect was found. Device-level IME and undo/redo testing was not done, as the PR states, but that is not evidence of a defect.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title is concise, uses the expected conventional format, and clearly describes the main mobile prose-direction fix.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Description checkPassedThe pull request description is complete and follows the required template. It explains the problem, change, scope and approval, verification steps, observed results, UI evidence, limits, and the agen…
Full details: Description check

Explanation

The pull request description is complete and follows the required template. It explains the problem, change, scope and approval, verification steps, observed results, UI evidence, limits, and the agent and harness used.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Added 1 commit

  • Merge branch 'main' into fix/mobile-bidi-text7c7db8c
Synced from GitHub

This works well, but I am hesitant to bringing in such a large patch to enriched-markdown, would you be willing to open up PRs to upstream some of these patches to their repo?

Added 2 commits

  • Merge remote-tracking branch 'github/main' into maria/takeover-23587-original3085410
  • fix(mobile): adapt prose direction to the current native renderer0702e1c

Note

Written by gpt-6.1-sol on behalf of Maria

@haithamassoli44, thanks for carrying the web word-majority policy into native rendering and preserving source text, code/chip exclusion, and authored bidi marks. your commits are intact; i merged main and updated the patch for its t3.16 renderer.

the update preserves main's padding removal and block-slot paths. obsolete padding assertions are removed. a new assertion in the existing clipboard test reproduced generated controls leaking through android table rich copy; the shared html exporter now filters them. two independent code reviewers approve 0702e1c134.

verification through blacksmith:

  • vp run check:changed: patch validation, format, lint, knip, and 34 package typechecks passed.
  • android native compilation and 12 focused composer/renderer tests passed, including table alignment/order and normal/table/partial clipboard exports.
  • 11 android word/ast cases, swift's 15 word votes and 12 document cases, ktlint, and detekt passed.

waiting: github marked ci, fingerprint, and preview workflows action_required; workflow approval is needed. the latest automatic bot review hit its review limit.

unverified: native ui/provider integration, refreshed before/after captures, ime/undo interactions, full native client builds, and uikit xctest. device access is turned off here. existing screenshots document the original t3.15 implementation. android's documented composer fence-body/neutral-line limits remain.

@haithamassoli44, upstreaming the renderer support remains a follow-up to Yash's request. native approval and current-device evidence are still needed before merging.

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

No changed runtime behavior could be verified on this Linux Boat VM. This is an unverifiable result, not a pass.

Inspected the description, discussion, reviews, diff, and exact open head 0702e1c134467d5e1aaf3e396821f4c5ec970583. The PR commits are by haithamassoli44 and maria-rcks; neither excluded maintainer authored a PR commit. GitCafe mirrors this as #23587.

The change runs in the native iOS/Android Markdown renderer and native chat/new-thread composers. The web client uses a separate implementation, so a Chrome session or a server-side Codex response would not exercise these changed views.

Device discovery returned:

text
1T3 device_list: Agent device access is turned off for this environment.
2$ timeout 30 adb devices -l
3List of devices attached
4[no devices]

The repository's test-t3-mobile skill explicitly requires stopping verification when its device tools or selected device are unavailable. No alternate device automation was installed. No main/PR dev server was started, no provider turn was submitted, and no source changes or pushes were made. There are no new runtime screenshots or recordings to attach.

Not verified

  • Original bug reproduction on github/main and comparison with the PR's exact head.
  • Real Codex gpt-6.1-sol responses rendered through either native client.
  • Arabic/Hebrew word-majority paragraphs, inline code order, quote borders, lists, tables, and English/fenced-code behavior.
  • Chat/new-thread typing, direction transitions, selection, chips, clipboard exports, IME, and undo/redo.
  • Native iOS/Android builds and device captures. These require enabled native device access and matching development clients.

Existing captures and earlier test reports in this PR were not treated as current runtime proof. Current visible check contexts are metadata/review jobs, not proof of native integration. CI, fingerprint, and preview runs for this head report action_required and still need workflow approval.