diff --git a/mast-react-vite/src/components/ui/action-parser.tsx b/mast-react-vite/src/components/ui/action-parser.tsx index 59fa374..9359751 100644 --- a/mast-react-vite/src/components/ui/action-parser.tsx +++ b/mast-react-vite/src/components/ui/action-parser.tsx @@ -7,6 +7,7 @@ import { Tag } from "@/components/ui/tag"; import { Project } from "@/components/ui/project"; import { Calendar as CalendarComponent } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { motion, AnimatePresence } from "motion/react"; export interface InputProps extends React.InputHTMLAttributes { @@ -24,6 +25,9 @@ const ActionParser = React.forwardRef( const [showShadow, setShowShadow] = React.useState(false); const [desktopCalendarOpen, setDesktopCalendarOpen] = React.useState(false); const [mobileCalendarOpen, setMobileCalendarOpen] = React.useState(false); + const [activeSuggestionType, setActiveSuggestionType] = React.useState(null); + const [showActiveButton, setShowActiveButton] = React.useState(false); + const [isExiting, setIsExiting] = React.useState(false); // Create refs for the suggestion containers and inputs const suggestionsRef = React.useRef(null); @@ -119,6 +123,18 @@ const ActionParser = React.forwardRef( setTimeout(() => focusInput(), 0); }; + const exitActiveMode = () => { + setIsExiting(true); + // First, fade back in the regular buttons and move active button back + setTimeout(() => { + // After animation completes, hide active button and reset states + setShowActiveButton(false); + setActiveSuggestionType(null); + setSuggestions([]); + setIsExiting(false); + }, 300); // Match animation duration + }; + const checkScrollShadow = (element: HTMLDivElement | null) => { if (!element) return; const hasMoreContent = element.scrollWidth > element.clientWidth; @@ -164,6 +180,8 @@ const ActionParser = React.forwardRef( } setSuggestions(tags); + setActiveSuggestionType('#'); + setShowActiveButton(true); } else if (lastWord.startsWith('+')) { // Extract the partial project (text after the +) @@ -188,13 +206,27 @@ const ActionParser = React.forwardRef( } setSuggestions(projects); + setActiveSuggestionType('+'); + setShowActiveButton(true); } else { - setSuggestions([]); + if (showActiveButton) { + exitActiveMode(); + } else { + setSuggestions([]); + setActiveSuggestionType(null); + setShowActiveButton(false); + } } } catch (error) { console.error("Error fetching suggestions:", error); - setSuggestions([]); + if (showActiveButton) { + exitActiveMode(); + } else { + setSuggestions([]); + setActiveSuggestionType(null); + setShowActiveButton(false); + } } }; @@ -359,31 +391,37 @@ React.useEffect(() => { onScroll={handleSuggestionsScroll} > {suggestions.map((suggestion, index) => { - const trimmedValue = (value as string || '').trim(); - const words = trimmedValue.split(/\s+/); - const lastWord = words[words.length - 1] || ''; + const trimmedValue = (value as string || '').trim(); + const words = trimmedValue.split(/\s+/); + const lastWord = words[words.length - 1] || ''; + + const handleClick = () => { + // Replace just the last word with the suggestion + if (activeSuggestionType === '#') { + words[words.length - 1] = `#${suggestion}`; + } else if (activeSuggestionType === '+') { + words[words.length - 1] = `+${suggestion}`; + } + + const newValue = words.join(' '); + props.onChange?.({ target: { value: newValue } } as any); + + // Reset suggestion state to trigger animation + setSuggestions([]); + setActiveSuggestionType(null); + setShowActiveButton(false); - const handleClick = () => { - // Replace just the last word with the suggestion - if (lastWord.startsWith('#')) { - words[words.length - 1] = `#${suggestion}`; - } else if (lastWord.startsWith('+')) { - words[words.length - 1] = `+${suggestion}`; - } - - const newValue = words.join(' '); - props.onChange?.({ target: { value: newValue } } as any); - setTimeout(() => focusInput(), 0); - }; + setTimeout(() => focusInput(), 0); + }; - // Return Tag or Project component based on input type - return lastWord.startsWith('#') ? ( + // Return Tag or Project component based on activeSuggestionType + return activeSuggestionType === '#' ? ( - ) : lastWord.startsWith('+') ? ( + ) : activeSuggestionType === '+' ? ( { })} - )} + )} - - - + {/* # Button */} + + + + + {/* + Button */} + + + + {/* Calendar Button */} + + + + + + + handleDateSelect(date, false)} + initialFocus + /> + + + + + {/* Flag Button */} + + - - - handleDateSelect(date, false)} - initialFocus - /> - - - -
- {suggestions.length > 0 && ( + + + +
+ {suggestions.length > 0 && showActiveButton && ( <> {showShadow && (
)} -
@@ -569,17 +704,20 @@ React.useEffect(() => { const newValue = words.join(' '); props.onChange?.({ target: { value: newValue } } as any); + + // Reset suggestion state + exitActiveMode(); setTimeout(() => focusInput(), 0); }; - // Return Tag or Project component based on input type - return lastWord.startsWith('#') ? ( + // Return Tag or Project component based on activeSuggestionType + return activeSuggestionType === '#' ? ( - ) : lastWord.startsWith('+') ? ( + ) : activeSuggestionType === '+' ? ( { ); })} + + + )}
- - )}