Compare commits

...

1 Commits

Author SHA1 Message Date
johnnyfish
62155a49f9 fix: prevent Portal rendering in SelectBox to fix search input focus in dialogs 2025-08-10 12:07:58 +03:00
2 changed files with 64 additions and 34 deletions

View File

@@ -11,21 +11,40 @@ const PopoverAnchor = PopoverPrimitive.Anchor;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground 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
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {
container?: HTMLElement | null;
}
>(
(
{ className, align = 'center', sideOffset = 4, container, ...props },
ref
) => {
const Content = (
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground 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
)}
{...props}
/>
);
// If container is explicitly null, don't use Portal
if (container === null) {
return Content;
}
// Otherwise, use Portal (default behavior)
return (
<PopoverPrimitive.Portal container={container}>
{Content}
</PopoverPrimitive.Portal>
);
}
);
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };

View File

@@ -94,6 +94,10 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
setOpen?.(isOpen);
setIsOpen(isOpen);
if (isOpen) {
setSearchTerm('');
}
setTimeout(() => (document.body.style.pointerEvents = ''), 500);
},
[setOpen]
@@ -225,6 +229,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
<CommandItem
className="flex items-center"
key={option.value}
value={option.label}
keywords={option.regex ? [option.regex] : undefined}
onSelect={() =>
handleSelect(
@@ -276,7 +281,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
);
return (
<Popover open={isOpen} onOpenChange={onOpenChange} modal={true}>
<Popover open={isOpen} onOpenChange={onOpenChange}>
<PopoverTrigger asChild tabIndex={0} onKeyDown={handleKeyDown}>
<div
className={cn(
@@ -350,6 +355,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
popoverClassName
)}
align="center"
container={null}
>
<Command
filter={(value, search, keywords) => {
@@ -417,25 +423,30 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
<CommandEmpty>
{emptyPlaceholder ?? 'No results found.'}
</CommandEmpty>
<ScrollArea>
<div className="max-h-64 w-full">
<CommandList className="max-h-fit w-full">
{hasGroups
? Object.entries(groups).map(
([groupName, groupOptions]) => (
<CommandGroup
key={groupName}
heading={groupName}
>
{groupOptions.map(
renderOption
)}
</CommandGroup>
)
)
: options.map(renderOption)}
</CommandList>
<div className="max-h-64">
{hasGroups ? (
Object.entries(groups).map(
([groupName, groupOptions]) => (
<CommandGroup
key={groupName}
heading={groupName}
>
<CommandList>
{groupOptions.map(
renderOption
)}
</CommandList>
</CommandGroup>
)
)
) : (
<CommandGroup>
<CommandList>
{options.map(renderOption)}
</CommandList>
</CommandGroup>
)}
</div>
</ScrollArea>
</Command>