Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
4.8 kB · 150 lines
TSX
at perf/paste
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151"use client";import { Input } from "components/Input";import { Combobox, ComboboxResult } from "components/Combobox";import { useActorTypeahead } from "src/hooks/useActorTypeahead";import { DotLoader } from "components/utils/DotLoader";import { theme } from "tailwind.config";import { AtmosphereAccount } from "components/Icons/AtmosphereAccount";
export const HandleInput = (props: { autoFocus?: boolean; action?: React.ReactNode; leading?: React.ReactNode; className?: string; large?: boolean; compact?: boolean; loading?: boolean; onSubmit?: (handle: string) => void;}) => { let { handleValue, setHandleValue, suggestions, setSuggestions, dropdownOpen, setDropdownOpen, highlighted, setHighlighted, } = useActorTypeahead();
const handleSelect = (handle?: string) => { const selected = handle ?? handleValue; if (!selected) return; setHandleValue(selected); setDropdownOpen(false); setSuggestions([]); setHighlighted(undefined); props.onSubmit?.(selected); };
const handles = suggestions.map((s) => s.handle);
return ( <Combobox open={dropdownOpen && !props.loading} onOpenChange={(open) => { 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={ <div className={`handleInput input-with-border relative py-0! flex items-center gap-2 w-full ${props.large && "px-2!"} ${props.className}`} style={ props.loading ? { backgroundColor: theme.colors["border-light"], color: theme.colors.tertiary, } : { backgroundColor: theme.colors["bg-page"], color: theme.colors.primary, } } > <div className="text-tertiary text-center shrink-0 flex justify-end h-full items-center"> {props.leading ?? <AtmosphereAccount />} </div> <Input autoFocus={props.autoFocus} className={`appearance-none! grow outline-none! min-w-0 ${props.large ? "py-1!" : props.compact ? "py-0!" : "py-0.5"}`} placeholder="atmosphere.handle" size={0} value={handleValue} onChange={(e) => setHandleValue(e.target.value)} onClick={(e) => e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); // handle Enter here (with the current handleValue) instead of // relying on the Combobox's window listener, which only submits // when a suggestion is highlighted. stopPropagation keeps that // listener from also firing with a stale value. e.stopPropagation(); handleSelect(highlighted); } }} autoComplete="off" disabled={props.loading} /> {props.loading ? ( <DotLoader /> ) : props.onSubmit ? ( <button type="button" onClick={(e) => { e.stopPropagation(); props.onSubmit!(handleValue); }} disabled={!handleValue} > {props.action} </button> ) : ( props.action )} </div> } > {suggestions.map((actor) => ( <ComboboxResult key={actor.did} result={actor.handle} highlighted={highlighted} setHighlighted={setHighlighted} onSelect={() => handleSelect(actor.handle)} className=" flex-row! gap-2! leading-snug text-sm" > {actor.avatar ? ( <img src={actor.avatar} alt="" className="w-6 h-6 rounded-full shrink-0 mr-2" /> ) : ( <div className="w-6 h-6 rounded-full bg-border shrink-0 mr-2" /> )} <div className="flex flex-col min-w-0 flex-1 text-left"> <div className="truncate font-bold"> {actor.displayName || actor.handle} </div> {actor.displayName && ( <div className="text-tertiary text-xs italic truncate"> @{actor.handle} </div> )} </div> </ComboboxResult> ))} </Combobox> );};