diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Options/PipOptionsMenu.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Options/PipOptionsMenu.tsx index a2e42b22..c9b0340c 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Options/PipOptionsMenu.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Options/PipOptionsMenu.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect } from 'react' import { RiMoreFill } from '@remixicon/react' import { Box, Button } from '@/primitives' import { css } from '@/styled-system/css' @@ -11,12 +11,41 @@ type PipOptionsMenuProps = { label: string } +// PiP-specific options menu positioned locally above the trigger button. export const PipOptionsMenu = ({ wrapperRef, isOpen, setIsOpen, label, }: PipOptionsMenuProps) => { + // Close menu when a menu item action completes (e.g., transcription, effects). + useEffect(() => { + if (!isOpen) return + const doc = wrapperRef.current?.ownerDocument ?? document + + const handleMenuItemClick = (event: MouseEvent) => { + const target = event.target as HTMLElement | null + const wrapper = wrapperRef.current + if (!wrapper || !target) return + + // Don't close if clicking the trigger button + if (wrapper.querySelector('button')?.contains(target)) return + + // Close if clicking a menu item (action will have fired) + if (target.closest('[role="menuitem"]')) { + // Use requestAnimationFrame to ensure action completes first, without visible delay + requestAnimationFrame(() => { + setIsOpen(false) + }) + } + } + + doc.addEventListener('click', handleMenuItemClick, true) + return () => { + doc.removeEventListener('click', handleMenuItemClick, true) + } + }, [isOpen, setIsOpen, wrapperRef]) + return (