import { useEffect, useRef, useState } from "react"; import { Check, ChevronDown } from "lucide-react"; import { RESEARCH_SCOPES, RESEARCH_SCOPE_DESCRIPTIONS, RESEARCH_SCOPE_EXAMPLES, RESEARCH_SCOPE_LABELS, type ResearchScope, } from "@/shared/researchScope"; type Props = { value: ResearchScope; onChange: (scope: ResearchScope) => void; /** Greys the whole control (e.g. a brand-keyword lookup) with this reason. */ disabledReason?: string; className?: string; "aria-label"?: string; }; /** * The shared research-scope selector: Exact URL / Subfolder / Domain / * Subdomains. A custom dropdown (not a native select) so each option can * explain what it covers. Every research input that accepts a URL or domain * renders this next to the input so scope is explicit instead of inferred. */ export function ResearchScopeSelect({ value, onChange, disabledReason, className = "", "aria-label": ariaLabel = "Research scope", }: Props) { const [open, setOpen] = useState(false); const [activeScope, setActiveScope] = useState(value); const containerRef = useRef(null); useEffect(() => { if (open) setActiveScope(value); }, [open, value]); // Close on outside click so it behaves like the surrounding native selects. useEffect(() => { if (!open) return; const handlePointerDown = (event: PointerEvent) => { const target = event.target; if (target instanceof Node && !containerRef.current?.contains(target)) { setOpen(false); } }; document.addEventListener("pointerdown", handlePointerDown); return () => document.removeEventListener("pointerdown", handlePointerDown); }, [open]); const select = (scope: ResearchScope) => { onChange(scope); setOpen(false); }; const moveActive = (step: 1 | -1) => { const currentIndex = RESEARCH_SCOPES.indexOf(activeScope); const nextIndex = Math.min( Math.max(currentIndex + step, 0), RESEARCH_SCOPES.length - 1, ); const next = RESEARCH_SCOPES[nextIndex]; if (next) setActiveScope(next); }; const handleKeyDown = (event: React.KeyboardEvent) => { if (!open) return; switch (event.key) { case "ArrowDown": event.preventDefault(); moveActive(1); break; case "ArrowUp": event.preventDefault(); moveActive(-1); break; case "Enter": case " ": event.preventDefault(); select(activeScope); break; case "Escape": event.preventDefault(); setOpen(false); break; } }; return (
{open ? (
    {RESEARCH_SCOPES.map((scope) => { const isSelected = scope === value; return (
  • ); })}
) : null}
); }