diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1c2f0f4..5e6c5b3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -24,6 +24,7 @@ import { useSavedProperties } from './hooks/useSavedProperties'; declare global { interface Window { __screenshot_ready?: boolean; + __map_idle?: boolean; } } diff --git a/frontend/src/components/map/AiFilterInput.tsx b/frontend/src/components/map/AiFilterInput.tsx index dac5d89..0850e26 100644 --- a/frontend/src/components/map/AiFilterInput.tsx +++ b/frontend/src/components/map/AiFilterInput.tsx @@ -1,6 +1,7 @@ import { memo, useState, useCallback, useEffect, useRef } from 'react'; import { SpinnerIcon } from '../ui/icons/SpinnerIcon'; import { SparklesIcon } from '../ui/icons/SparklesIcon'; +import { ChevronIcon } from '../ui/icons/ChevronIcon'; import type { AiFilterErrorType } from '../../hooks/useAiFilters'; const EXAMPLE_QUERIES = [ @@ -65,18 +66,45 @@ export default memo(function AiFilterInput({ const [expanded, setExpanded] = useState(false); const loadingMessage = useLoadingMessage(loading); const containerRef = useRef(null); + const textareaRef = useRef(null); + + const queryRef = useRef(query); + queryRef.current = query; useEffect(() => { if (!expanded || loading) return; const handler = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { - setExpanded(false); + if (!queryRef.current.trim()) setExpanded(false); } }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [expanded, loading]); + const resizeTextarea = useCallback(() => { + const ta = textareaRef.current; + if (!ta) return; + ta.style.height = 'auto'; + ta.style.height = `${ta.scrollHeight}px`; + }, []); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + const trimmed = query.trim(); + if (!trimmed || loading) return; + if (!isLoggedIn) { + onLoginRequired(); + return; + } + onSubmit(trimmed); + } + }, + [query, loading, isLoggedIn, onLoginRequired, onSubmit] + ); + const handleSubmit = useCallback( (e: React.FormEvent) => { e.preventDefault(); @@ -132,14 +160,27 @@ export default memo(function AiFilterInput({ describe what you're looking for + -
- +