Derive mobile driver overlay collapse state (#3170)

This commit is contained in:
Neil
2026-05-29 21:14:35 -04:00
committed by GitHub
parent 087320556b
commit 8357929349
3 changed files with 75 additions and 10 deletions
@@ -3,6 +3,10 @@ import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import type { DriverState } from '@/lib/pane-manager/mobile-driver-state'
import { shouldFocusMobileDriverAction } from './mobile-driver-overlay-focus'
import {
createMobileDriverOverlayCollapseState,
getMobileDriverOverlayCollapseState
} from './mobile-driver-overlay-collapse'
type Props = {
driver: DriverState
@@ -25,7 +29,9 @@ export function MobileDriverOverlay({
const isHeldAtPhoneFit = !isMobileDriving && hasFitOverride
const driverClientId = driver.kind === 'mobile' ? driver.clientId : null
const [collapsed, setCollapsed] = useState(false)
const [collapseState, setCollapseState] = useState(() =>
createMobileDriverOverlayCollapseState(driverClientId)
)
const [actionPending, setActionPending] = useState(false)
const mountedRef = useRef(true)
@@ -36,13 +42,12 @@ export function MobileDriverOverlay({
[]
)
// Re-expand on driver flip so a new mobile actor is loud, not silent.
useEffect(() => {
if (!isMobileDriving) {
return
}
setCollapsed(false)
}, [isMobileDriving, driverClientId])
const currentCollapseState = getMobileDriverOverlayCollapseState(collapseState, driverClientId)
// Why: a new mobile actor must be loud even if the prior driver was collapsed.
if (currentCollapseState !== collapseState) {
setCollapseState(currentCollapseState)
}
const collapsed = currentCollapseState.collapsed
if (!isMobileDriving && !isHeldAtPhoneFit) {
return null
@@ -82,7 +87,7 @@ export function MobileDriverOverlay({
<LockChip
actionPending={actionPending}
onAction={handleAction}
onExpand={() => setCollapsed(false)}
onExpand={() => setCollapseState(createMobileDriverOverlayCollapseState(driverClientId))}
rootClassName={rootClassName}
/>
)
@@ -96,7 +101,7 @@ export function MobileDriverOverlay({
actionLabel="Take back"
actionPending={actionPending}
onAction={handleAction}
onCollapse={() => setCollapsed(true)}
onCollapse={() => setCollapseState({ driverClientId, collapsed: true })}
tone="driving"
rootClassName={rootClassName}
/>
@@ -0,0 +1,35 @@
import { describe, expect, it } from 'vitest'
import {
createMobileDriverOverlayCollapseState,
getMobileDriverOverlayCollapseState
} from './mobile-driver-overlay-collapse'
describe('mobile-driver-overlay-collapse', () => {
it('preserves collapsed state for the same mobile driver', () => {
const state = { driverClientId: 'phone-1', collapsed: true }
expect(getMobileDriverOverlayCollapseState(state, 'phone-1')).toBe(state)
})
it('re-expands when a new mobile driver takes over', () => {
expect(
getMobileDriverOverlayCollapseState({ driverClientId: 'phone-1', collapsed: true }, 'phone-2')
).toEqual({
driverClientId: 'phone-2',
collapsed: false
})
})
it('resets after held-fit mode before the same phone drives again', () => {
const heldState = getMobileDriverOverlayCollapseState(
{ driverClientId: 'phone-1', collapsed: true },
null
)
expect(heldState).toEqual(createMobileDriverOverlayCollapseState(null))
expect(getMobileDriverOverlayCollapseState(heldState, 'phone-1')).toEqual({
driverClientId: 'phone-1',
collapsed: false
})
})
})
@@ -0,0 +1,25 @@
export type MobileDriverOverlayCollapseState = {
driverClientId: string | null
collapsed: boolean
}
export function getMobileDriverOverlayCollapseState(
state: MobileDriverOverlayCollapseState,
driverClientId: string | null
): MobileDriverOverlayCollapseState {
return state.driverClientId === driverClientId
? state
: {
driverClientId,
collapsed: false
}
}
export function createMobileDriverOverlayCollapseState(
driverClientId: string | null
): MobileDriverOverlayCollapseState {
return {
driverClientId,
collapsed: false
}
}