Open image count options from input

This commit is contained in:
FengLee
2026-05-12 20:01:09 +08:00
parent 493ae83d2d
commit 618e58b04a

View File

@@ -1,12 +1,7 @@
'use client';
import { useRef, useState } from 'react';
import { ChevronDown } from 'lucide-react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
@@ -31,41 +26,78 @@ interface ImageCountComboboxProps {
}
export function ImageCountCombobox({ value, onChange, className }: ImageCountComboboxProps) {
const [open, setOpen] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const selectValue = (nextValue: string) => {
onChange(nextValue);
setOpen(false);
inputRef.current?.focus();
};
return (
<div className={cn('relative w-28', className)}>
<div
className={cn('relative w-28', className)}
onBlur={event => {
if (!event.currentTarget.contains(event.relatedTarget)) {
setOpen(false);
}
}}
>
<Input
ref={inputRef}
aria-label="生成数量"
aria-expanded={open}
aria-haspopup="listbox"
className="h-10 pr-9 text-center"
inputMode="numeric"
maxLength={2}
placeholder="自动"
role="combobox"
value={value === 'auto' ? '' : value}
onBlur={event => onChange(normalizeCountValue(event.currentTarget.value))}
onChange={event => onChange(normalizeCountValue(event.currentTarget.value))}
onChange={event => {
setOpen(true);
onChange(normalizeCountValue(event.currentTarget.value));
}}
onClick={() => setOpen(true)}
onFocus={() => setOpen(true)}
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
aria-label="选择生成数量"
className="text-muted-foreground hover:text-foreground focus-visible:border-primary/70 focus-visible:ring-primary/30 absolute top-0 right-0 flex h-10 w-9 items-center justify-center rounded-r-md outline-none focus-visible:ring-2"
>
<ChevronDown className="size-4" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="min-w-28">
<button
type="button"
aria-label="选择生成数量"
className="text-muted-foreground hover:text-foreground focus-visible:border-primary/70 focus-visible:ring-primary/30 absolute top-0 right-0 flex h-10 w-9 items-center justify-center rounded-r-md outline-none focus-visible:ring-2"
onMouseDown={event => event.preventDefault()}
onClick={() => {
setOpen(current => !current);
inputRef.current?.focus();
}}
>
<ChevronDown className={cn('size-4 transition-transform', open && 'rotate-180')} />
</button>
{open && (
<div
role="listbox"
className="glass-popover absolute top-full left-0 z-[100] mt-1 w-28 rounded-md p-1"
>
{IMAGE_COUNT_OPTIONS.map(option => (
<DropdownMenuItem
<button
key={option.value}
onSelect={() => onChange(option.value)}
className={cn(value === option.value && 'bg-accent text-accent-foreground')}
type="button"
role="option"
aria-selected={value === option.value}
className={cn(
'focus:bg-accent focus:text-accent-foreground flex min-h-8 w-full items-center rounded-sm px-2 text-sm outline-none',
value === option.value && 'bg-accent text-accent-foreground',
)}
onMouseDown={event => event.preventDefault()}
onClick={() => selectValue(option.value)}
>
{option.label}
</DropdownMenuItem>
</button>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
)}
</div>
);
}