mirror of
https://github.com/stablyai/orca.git
synced 2026-11-06 12:07:58 +00:00
93ed192025545c597a5df3c9804fb7c19085eaa0
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e9ec63168f |
fix(mobile): hold-to-dictate, repeat keys and the browser long-press survive the page's long-press (#24277)
On the OTA page a held press died ~500 ms in: the WebView's long-press selected nearby text and that selection's selectionchange/touchcancel ended the press. Page text is now unselectable unless it opts in (as native), hold surfaces declare onLongPress, the browser pane refuses contextmenu termination, and the chat mic's swapped icons no longer steal the touch target. |
||
|
|
ba858ee446 |
feat(mobile): the keyboard covers the page like a native screen, and the shell says its height (#23110)
The shell no longer shortens the WebView for the keyboard; it publishes the keyboard height like the safe-area insets, so native's keyboard lift, refit hold and dismiss key run on the page unchanged. Keyboard and inset arithmetic read the shell's OS through a host-os seam. One page-version floor (manifest pageVersion, shell floor 1) replaces per-feature accept negotiation; a page below the floor gets the existing update wall, a desktop with no bundle keeps native screens. iOS shell drops the form accessory bar and its own keyboard observers. Native session screens untouched. |
||
|
|
564f135248 |
fix(mobile): an accessory Enter ends the field's editing session, and the page's Enter survives a composition (#22300)
* test(config): the page's live input never submits under an open composition The emulator's page-only defect, in a browser: an Android soft keyboard keeps a composition open over the word being typed, so the Enter keydown carries `isComposing: true`, which is the condition react-native-web reads to skip `onSubmitEditing` entirely. Nothing reaches the terminal and the field keeps the text. The probe route now mounts `useTerminalLiveInputCommit` and the command dock's own field props, so keys enter through the browser rather than through a handle that calls the hook directly. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * style(config): format the live-input render check Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): the page's live input submits under an open composition react-native-web's keydown handler withholds `onSubmitEditing` whenever the Enter keydown reports a composition — `nativeEvent.isComposing`, or the Android `keyCode` 229 that stands for it — which is a soft keyboard's normal state mid-word. Nothing reached the terminal and the field kept the text. Native Android's editor action has no such suppression, which is why only the page showed it. The field now also claims `beforeinput`/`insertLineBreak`, the browser's own end-of-line signal. react-native-web cancels every keydown it does submit on, so that event exists only in the cases it dropped, never twice; an IME still choosing a candidate reports `insertCompositionText` and is left alone. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): list the live-input submit binding, and repin the session closure The `.web.ts` sibling needed its row in `web-overrides.json`, whose check lists exactly the overrides on disk. The session route's page closure moves with it: the callback ref and the binding it resolves to are both local, and the native sibling stays out, which is what the pair is for. modules 4207 -> 4209 (+2) local modules 1021 -> 1023 (+2) Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): the key bar's Enter chip leaves the sent text in the live field The device trace's variant (a), which is what shots/23 was: the chip emits no DOM key event, so react-native-web's submit handling never runs and the accessory hook is the only thing that could end the field's editing session. With nothing held it takes the send-now branch, which flushes nothing and writes neither the capture state nor the field, so the text the PTY already echoed stays put and the next keystrokes append to it. Not a page defect: the held-text fallback only holds a trailing non-ASCII run, so ASCII leaves nothing held on native either. The unit case is on the shared hook for that reason. The probe route now models what the send actions do with 'allow-raw', so the check can see a control sent twice or not at all. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(config): the buffered command field has the live field's Enter gate too Three cases, one red. A plain Enter sends the draft and empties the field, which is `beginBufferedTerminalDraftSend`'s doing and stays a guard. The key bar's Enter chip in buffered mode is a plain terminal key: the accessory hook declines at its live-handle guard, one carriage return goes out and the draft is untouched, also a guard. The red one is Enter under an open composition. This field reaches its send through `onSubmitEditing` alone, so react-native-web's keydown gate swallows it exactly as it did for the live field, and the draft neither goes out nor leaves the field. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): an accessory Enter ends the field's editing session, on both fields Two defects, one rule: after a control that ends the line, the terminal owns the echoed text and the field's editing session is over. The key bar's Enter chip (device trace, variant (a)) emits no DOM key event, so only the accessory hook could end that session. Its held-text branch does, through the flush; with nothing held it took `send-now`, which flushed nothing and wrote neither the capture state nor the field. Not page-only: the held-text fallback holds a trailing non-ASCII run, so ASCII leaves nothing held on native either. `send-now` now takes the same flush when the bytes end the line, and still defers the send to its caller so exactly one return goes out. The buffered command field had the live field's composition gate, because it also reaches its send through `onSubmitEditing` alone. It binds the page's line-break signal now too, which is why the seam is named for a terminal text field rather than for the live input. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): the submit binding holds the handler its first render was given Found by pullfrog on #22300. The binding refreshed its handler ref only when the callback identity changed, so a caller memoizing on an empty dependency list was bound once and never again. The buffered command field does exactly that: its submit closes over handleSend, a per-render function whose guard reads client and activeHandle, both null until effects supply them, so the page's line-break submit could never pass that guard. The probe route now carries the same two paths the dock has — a fresh per-render function on the field's onSubmitEditing prop, and the memoized closure on the binding — because the working prop path is what hid this. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): the buffered field's page submit reaches a live handleSend Found by pullfrog on #22300. `submitBufferedDraft` was memoized on an empty dependency list, which froze the per-render `handleSend` it calls. That guard reads `client`, `activeHandle` and `canSend`, none of which the first render has, so the page's line-break submit could never pass it. The field's own `onSubmitEditing` prop kept working, which is what hid it. The handler is per-render now, and the binding refreshes its handler ref on every commit rather than when the callback identity changes — the ref exists so the listener always reaches the newest handler, and it should not rest on a caller's memoization. That second half fixes nothing on its own: a `useCallback` with `[]` returns one function object for the life of the component, so no ref can find a newer closure behind it. The source census is what catches that, and it is red against the frozen handler. The probe route is back on the dock's shape, per-render on both submit paths, with a note saying why a route that writes its own submit cannot catch this. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): the page's buffered submit reaches a handleSend that can send The census beside this reads one spelling of a frozen handler. This reads the behaviour: the send-actions hook is rendered first as a session is before its effects land, with no client and no handle, then again as it is after, and the listener the page's binding attached has to reach the second one. Asserted on the params that reach the client, not on a call count. Red with the `useCallback` restored, and red with a `useMemo` in its place, which is the point of testing the behaviour rather than the spelling. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): declare the two mock arrays instead of asserting them `[] as Array<T>` inside the hoisted factory was a type assertion with nothing to explain: the arrays are built here, so a checked declaration says the same thing and the quality gate has nothing to flag. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): the submit binding stops claiming a cure it does not have The handler ref refreshed on every commit rather than on the callback identity, and the docblock called that the reason the seam exists. It is not: a caller that freezes its closure hands this hook one function object for the life of the component, so no ref finds a newer one, and a caller that does not freeze it changes identity every render and refreshes the dependency anyway. Measured both ways. The dependency is back, and the prose says only what the code does. The rule that does hold — a bound handler must not be frozen on an empty dependency list — is stated where it is enforced, in the wiring census, with the behavioural check named beside it. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): the submit binding's latest-ref drops its dependency list React Doctor flags the dependency twice, once per bound field: both of the dock's field submits are rebuilt every render, because the handleSend they read is, so `[onSubmit]` is a new value every time and there is nothing to compare. The tree's other latest-refs are written without a list for the same reason — use-mobile-web-shell-bridge.ts:148 is the one this follows. The comment says what the ref does, which is mirror the newest closure after each commit so callers may pass per-render handlers. It claims nothing about a caller that freezes one; that rule is still the wiring census's. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb |
||
|
|
cb94265cf4 |
fix(mobile): restore session parity after extraction
(cherry picked from commit
|
||
|
|
7caf7ab1e1 |
refactor(mobile): split session and terminal surfaces
(cherry picked from commit
|