返回 DeepSeek-Reasonix
ComposerChoice.tsx
根目录 / desktop / frontend / src / components / ComposerChoice.tsx
1 import { useEffect, useRef, useState, type ReactNode } from "react";
2 import { Check, ChevronDown } from "lucide-react";
3 import { AnchoredPopover } from "./AnchoredPopover";
4
5 export function ComposerChoice({ label, ariaLabel, icon, showChevron, value, options, disabled, dismissSignal, onPick, tone }: {
6 label: string;
7 ariaLabel?: string;
8 showChevron?: boolean;
9 icon?: ReactNode;
10 value: string;
11 options: { value: string; label: string; badge?: string; description?: string; icon?: ReactNode; title?: string }[];
12 disabled?: boolean;
13 dismissSignal?: number;
14 onPick: (value: string) => void;
15 tone?: string;
16 }) {
17 const [open, setOpen] = useState(false);
18 const anchor = useRef<HTMLButtonElement>(null);
19 useEffect(() => { if (disabled || dismissSignal !== undefined) setOpen(false); }, [disabled, dismissSignal]);
20 return <>
21 <button ref={anchor} type="button" className={`composer-choice ${tone || ""}`} disabled={disabled}
22 aria-label={ariaLabel || label} aria-haspopup="menu" aria-expanded={open && !disabled} onClick={() => setOpen(!open)}>
23 {icon}<span>{label}</span>{(showChevron ?? !icon) && <ChevronDown size={12} />}
24 </button>
25 <AnchoredPopover open={open && !disabled} anchorRef={anchor} onClose={() => setOpen(false)} className="composer-access-menu composer-menu-surface" align="start">
26 <div role="menu" aria-label={ariaLabel || label}>
27 {options.map(option => <button key={option.value} type="button" role="menuitemradio"
28 data-value={option.value} title={option.title}
29 aria-checked={value === option.value} className={`composer-access-menu__item${value === option.value ? " composer-access-menu__item--active" : ""}`}
30 onClick={() => { setOpen(false); onPick(option.value); }}>
31 {option.icon}<span className="composer-access-menu__copy"><span className="composer-access-menu__heading"><span className="composer-access-menu__title">{option.label}</span>
32 {option.badge && <span className="composer-access-menu__badge">{option.badge}</span>}</span>
33 {option.description && <span className="composer-access-menu__desc">{option.description}</span>}</span>
34 {value === option.value && <Check size={14} />}
35 </button>)}
36 </div>
37 </AnchoredPopover>
38 </>;
39 }
40
40 lines Plain Text