diff --git a/web/apps/dashboard/components/ui/combobox.tsx b/web/apps/dashboard/components/ui/combobox.tsx index b05f153c09..ab62fa0299 100644 --- a/web/apps/dashboard/components/ui/combobox.tsx +++ b/web/apps/dashboard/components/ui/combobox.tsx @@ -111,7 +111,7 @@ export function Combobox({ ); return ( - +
{leftIcon && (
{leftIcon}
@@ -149,21 +149,35 @@ export function Combobox({
{ + // Prevent auto-focus to allow proper keyboard navigation + e.preventDefault(); + }} > - + { + // Allow keyboard navigation within the combobox + if ( + e.key === "ArrowDown" || + e.key === "ArrowUp" || + e.key === "Enter" || + e.key === "Escape" + ) { + e.stopPropagation(); + } + }} + > { - if (e.key !== "Enter" && e.key !== " ") { - e.stopPropagation(); - } + // Prevent propagation to Dialog but allow command list navigation + e.stopPropagation(); }} placeholder={searchPlaceholder} className="text-xs placeholder:text-xs placeholder:text-accent-8" /> - + {emptyMessage} {options.map((option) => ( diff --git a/web/apps/dashboard/components/ui/form-combobox.tsx b/web/apps/dashboard/components/ui/form-combobox.tsx index e7b9e4f527..910313128a 100644 --- a/web/apps/dashboard/components/ui/form-combobox.tsx +++ b/web/apps/dashboard/components/ui/form-combobox.tsx @@ -57,8 +57,9 @@ export const FormCombobox = React.forwardRef( }, ref, ) => { + const generatedId = React.useId(); const inputVariant = error ? "error" : variant; - const inputId = propId || React.useId(); + const inputId = propId || generatedId; const descriptionId = `${inputId}-helper`; const errorId = `${inputId}-error`; diff --git a/web/internal/ui/src/components/dialog/dialog.tsx b/web/internal/ui/src/components/dialog/dialog.tsx index f5dbe2bbf1..9779cb3350 100644 --- a/web/internal/ui/src/components/dialog/dialog.tsx +++ b/web/internal/ui/src/components/dialog/dialog.tsx @@ -74,6 +74,11 @@ const DialogContent = React.forwardRef< className, )} onKeyDown={(e) => { + // Allow keyboard navigation for nested interactive elements + if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter") { + // Let these events propagate to nested components like Combobox + return; + } // Prevent Tab key from closing the dialog if (e.key === "Tab") { e.stopPropagation(); @@ -106,6 +111,13 @@ const DialogContent = React.forwardRef< // Also prevent interact outside events when preventOutsideClose is true if (preventOutsideClose) { e.preventDefault(); + return; + } + + // Allow interactions with nested popovers/portals (e.g., Combobox dropdowns) + const target = e.target as HTMLElement; + if (target.closest('[role="listbox"]') || target.closest("[cmdk-root]")) { + e.preventDefault(); } }} {...props} diff --git a/web/internal/ui/src/components/dialog/navigable-dialog.tsx b/web/internal/ui/src/components/dialog/navigable-dialog.tsx index 27836e17f4..8f6b5d26da 100644 --- a/web/internal/ui/src/components/dialog/navigable-dialog.tsx +++ b/web/internal/ui/src/components/dialog/navigable-dialog.tsx @@ -68,7 +68,18 @@ const NavigableDialogRoot = ({ e.stopPropagation()} + onKeyDown={(e) => { + // Allow keyboard events to propagate to nested components like Combobox + if ( + e.key === "ArrowDown" || + e.key === "ArrowUp" || + e.key === "Enter" || + e.key === "Escape" + ) { + return; + } + e.stopPropagation(); + }} className={cn( "drop-shadow-2xl transform-gpu border-grayA-4 overflow-hidden !rounded-2xl p-0 gap-0 flex flex-col max-h-[90vh]", dialogClassName, @@ -225,7 +236,7 @@ const NavigableDialogContent = ({ return (
-
+
{items.map((item) => { const isActive = item.id === activeId; return ( @@ -258,7 +269,11 @@ const NavigableDialogBody = ({ children: ReactNode; className?: string; }) => { - return
{children}
; + return ( +
+ {children} +
+ ); }; NavigableDialogBody.displayName = "NavigableDialogBody"; diff --git a/web/internal/ui/src/components/dialog/popover.tsx b/web/internal/ui/src/components/dialog/popover.tsx index 7637d85930..c0e008f895 100644 --- a/web/internal/ui/src/components/dialog/popover.tsx +++ b/web/internal/ui/src/components/dialog/popover.tsx @@ -17,7 +17,7 @@ const PopoverContent = React.forwardRef< align={align} sideOffset={sideOffset} className={cn( - "z-[150] w-72 overflow-hidden rounded-lg border border-grayA-4 bg-gray-2 p-4 text-gray-12 shadow-md outline-none", + "z-[200] w-72 rounded-lg border border-grayA-4 bg-gray-2 p-4 text-gray-12 shadow-md outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className,