mirror of
https://github.com/stablyai/orca.git
synced 2026-10-26 08:02:44 +00:00
fix(mobile): announce the stale-status swap and pin the hold's cancel path
The row rewrites itself from "Agent is working" to "Agent status stale" with no live region, so screen-reader users got no cue for the exact state this change exists to communicate (WCAG 2.1 SC 4.1.3). Matches the send-error banner's existing pattern in this view. Also covers the anti-flicker guarantee itself: a link that recovers inside the 600ms hold must cancel the armed timer, not merely lose the race with it.
This commit is contained in:
@@ -41,7 +41,9 @@ export function MobileAgentWorkingIndicator({
|
||||
return (
|
||||
// Not dimmed: the label is the only thing left carrying the state once the
|
||||
// dots go, and fading it under `textMuted` drops it below AA on `bgBase`.
|
||||
<View style={styles.row}>
|
||||
// The live region is constant, not toggled with `stale` — Android only
|
||||
// announces content changes once the mode is already set.
|
||||
<View style={styles.row} accessibilityLiveRegion="polite">
|
||||
<Text style={styles.label}>{stale ? 'Agent status stale' : 'Agent is working'}</Text>
|
||||
{stale ? null : (
|
||||
<View style={styles.dots}>
|
||||
|
||||
@@ -252,6 +252,22 @@ describe('MobileNativeChatView', () => {
|
||||
expect(stopButton().props.disabled).toBe(true)
|
||||
})
|
||||
|
||||
it('never goes stale when the link recovers inside the hold', async () => {
|
||||
vi.useFakeTimers()
|
||||
await render({ agentWorking: true, inputLockReason: 'disconnected' })
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(300)
|
||||
})
|
||||
await relock('waiting')
|
||||
await settleLockDebounce()
|
||||
|
||||
// The armed timer has to be cancelled, not just overruled — a surviving one
|
||||
// would fire late and mute a row whose transport is already back.
|
||||
expect(workingIndicator().props.stale).toBe(false)
|
||||
expect(stopButton().props.disabled).toBe(false)
|
||||
})
|
||||
|
||||
it('restores a live Stop as soon as the transport reconnects', async () => {
|
||||
vi.useFakeTimers()
|
||||
await render({ agentWorking: true, inputLockReason: 'disconnected' })
|
||||
|
||||
Reference in New Issue
Block a user