diff --git a/components/Combobox.tsx b/components/Combobox.tsx index b001d0ae..30085c25 100644 --- a/components/Combobox.tsx +++ b/components/Combobox.tsx @@ -15,12 +15,16 @@ export const Combobox = ({ showSearch, trigger, triggerClassName, + className, sideOffset, open: openProp, + zIndex, }: { children: React.ReactNode; trigger?: React.ReactNode; triggerClassName?: string; + className?: string; + width?: string; results: string[]; onSelect?: () => void; onOpenChange?: (open: boolean) => void; @@ -31,6 +35,7 @@ export const Combobox = ({ showSearch?: boolean; sideOffset?: number; open?: boolean; + zIndex?: number; }) => { let ref = useRef(null); let [internalOpen, setInternalOpen] = useState(false); @@ -106,10 +111,12 @@ export const Combobox = ({ collisionPadding={16} ref={ref} onOpenAutoFocus={(e) => e.preventDefault()} + style={zIndex !== undefined ? { zIndex } : undefined} className={` commandMenuContent group/cmd-menu z-20 w-[264px] flex data-[side=top]:items-end items-start + ${className} `} > diff --git a/components/Subscribe/HandleInput.tsx b/components/Subscribe/HandleInput.tsx index c0743273..6526c829 100644 --- a/components/Subscribe/HandleInput.tsx +++ b/components/Subscribe/HandleInput.tsx @@ -1,7 +1,7 @@ "use client"; import { Agent } from "@atproto/api"; import { Input } from "components/Input"; -import * as RadixPopover from "@radix-ui/react-popover"; +import { Combobox, ComboboxResult } from "components/Combobox"; import { useState } from "react"; import { useDebouncedEffect } from "src/hooks/useDebouncedEffect"; @@ -22,7 +22,7 @@ export const HandleInput = (props: { let [handleValue, setHandleValue] = useState(""); let [suggestions, setSuggestions] = useState([]); let [dropdownOpen, setDropdownOpen] = useState(false); - let [selectedIndex, setSelectedIndex] = useState(0); + let [highlighted, setHighlighted] = useState(undefined); useDebouncedEffect( async () => { @@ -44,64 +44,64 @@ export const HandleInput = (props: { })); setSuggestions(actors); setDropdownOpen(actors.length > 0); - setSelectedIndex(0); }, 300, [handleValue], ); - const handleSelect = (selected: string) => { + const handleSelect = (handle?: string) => { + const selected = handle ?? handleValue; + if (!selected) return; setHandleValue(selected); setDropdownOpen(false); setSuggestions([]); + setHighlighted(undefined); props.onSubmit?.(selected); }; - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "ArrowDown") { - if (!dropdownOpen) return; - e.preventDefault(); - setSelectedIndex((i) => Math.min(i + 1, suggestions.length - 1)); - } else if (e.key === "ArrowUp") { - if (!dropdownOpen) return; - e.preventDefault(); - setSelectedIndex((i) => Math.max(i - 1, 0)); - } else if (e.key === "Enter") { - if (dropdownOpen && suggestions[selectedIndex]) { - e.preventDefault(); - handleSelect(suggestions[selectedIndex].handle); - } else if (!dropdownOpen && handleValue) { - e.preventDefault(); - props.onSubmit?.(handleValue); - } - } else if (e.key === "Escape") { - setDropdownOpen(false); - } - }; + const handles = suggestions.map((s) => s.handle); return ( - - + { + if (!open) { + setDropdownOpen(false); + setHighlighted(undefined); + } + }} + results={handles} + highlighted={highlighted} + setHighlighted={setHighlighted} + onSelect={() => handleSelect(highlighted)} + zIndex={60} + sideOffset={4} + className="w-(--radix-popover-trigger-width)!" + trigger={
-
+
@
setHandleValue(e.target.value)} - onKeyDown={handleKeyDown} + onClick={(e) => e.stopPropagation()} + onPointerDown={(e) => e.stopPropagation()} autoComplete="off" /> {props.onSubmit ? (
- - - e.preventDefault()} - className="dropdownMenu z-20 bg-bg-page flex flex-col p-1 gap-1 text-primary border border-border rounded-md shadow-md w-(--radix-popover-trigger-width)" + } + > + {suggestions.map((actor) => ( + handleSelect(actor.handle)} + className=" flex-row! gap-2! leading-snug text-sm" > - {suggestions.map((actor, index) => ( - - ))} - - - + )} +
+ + ))} +
); };