mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
fix: guard terminal mobile driver action from root ref (#3552)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useId, useRef, useState, type ReactElement } from 'react'
|
||||
import { useCallback, useEffect, useId, useRef, useState, type ReactElement } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { DriverState } from '@/lib/pane-manager/mobile-driver-state'
|
||||
@@ -33,14 +33,11 @@ export function MobileDriverOverlay({
|
||||
createMobileDriverOverlayCollapseState(driverClientId)
|
||||
)
|
||||
const [actionPending, setActionPending] = useState(false)
|
||||
const mountedRef = useRef(true)
|
||||
const mountedRef = useRef(false)
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
mountedRef.current = false
|
||||
},
|
||||
[]
|
||||
)
|
||||
const setOverlayRootRef = useCallback((node: HTMLDivElement | null): void => {
|
||||
mountedRef.current = node !== null
|
||||
}, [])
|
||||
|
||||
const currentCollapseState = getMobileDriverOverlayCollapseState(collapseState, driverClientId)
|
||||
// Why: a new mobile actor must be loud even if the prior driver was collapsed.
|
||||
@@ -77,6 +74,7 @@ export function MobileDriverOverlay({
|
||||
actionPending={actionPending}
|
||||
onAction={handleAction}
|
||||
tone="held"
|
||||
rootRef={setOverlayRootRef}
|
||||
rootClassName={rootClassName}
|
||||
/>
|
||||
)
|
||||
@@ -88,6 +86,7 @@ export function MobileDriverOverlay({
|
||||
actionPending={actionPending}
|
||||
onAction={handleAction}
|
||||
onExpand={() => setCollapseState(createMobileDriverOverlayCollapseState(driverClientId))}
|
||||
rootRef={setOverlayRootRef}
|
||||
rootClassName={rootClassName}
|
||||
/>
|
||||
)
|
||||
@@ -103,6 +102,7 @@ export function MobileDriverOverlay({
|
||||
onAction={handleAction}
|
||||
onCollapse={() => setCollapseState({ driverClientId, collapsed: true })}
|
||||
tone="driving"
|
||||
rootRef={setOverlayRootRef}
|
||||
rootClassName={rootClassName}
|
||||
/>
|
||||
)
|
||||
@@ -117,6 +117,7 @@ type LoudOverlayProps = {
|
||||
onAction: () => void | Promise<void>
|
||||
onCollapse?: () => void
|
||||
tone: 'driving' | 'held'
|
||||
rootRef?: (node: HTMLDivElement | null) => void
|
||||
rootClassName?: string
|
||||
}
|
||||
|
||||
@@ -129,12 +130,20 @@ function LoudOverlay({
|
||||
onAction,
|
||||
onCollapse,
|
||||
tone,
|
||||
rootRef: outerRootRef,
|
||||
rootClassName
|
||||
}: LoudOverlayProps): ReactElement {
|
||||
const titleId = useId()
|
||||
const bodyId = useId()
|
||||
const rootRef = useRef<HTMLDivElement>(null)
|
||||
const actionRef = useRef<HTMLButtonElement>(null)
|
||||
const setRootRef = useCallback(
|
||||
(node: HTMLDivElement | null): void => {
|
||||
rootRef.current = node
|
||||
outerRootRef?.(node)
|
||||
},
|
||||
[outerRootRef]
|
||||
)
|
||||
// Why: focus the recovery action on mount only when the user isn't already
|
||||
// typing into another input (composer, command palette, settings field).
|
||||
// Unconditional autoFocus yanks focus on every overlay mount, so a phone
|
||||
@@ -150,7 +159,7 @@ function LoudOverlay({
|
||||
// lock UI must not add a pane-wide scrim or blur over the live stream.
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
ref={setRootRef}
|
||||
role="dialog"
|
||||
aria-live="assertive"
|
||||
aria-labelledby={titleId}
|
||||
@@ -203,12 +212,20 @@ type ChipProps = {
|
||||
actionPending: boolean
|
||||
onAction: () => void | Promise<void>
|
||||
onExpand: () => void
|
||||
rootRef?: (node: HTMLDivElement | null) => void
|
||||
rootClassName?: string
|
||||
}
|
||||
|
||||
function LockChip({ actionPending, onAction, onExpand, rootClassName }: ChipProps): ReactElement {
|
||||
function LockChip({
|
||||
actionPending,
|
||||
onAction,
|
||||
onExpand,
|
||||
rootRef,
|
||||
rootClassName
|
||||
}: ChipProps): ReactElement {
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className={cn(
|
||||
'absolute right-2 top-2 z-50 flex items-center gap-1.5 rounded-full border border-border bg-card px-2 py-1 text-xs font-medium text-card-foreground shadow-xs',
|
||||
rootClassName
|
||||
|
||||
Reference in New Issue
Block a user