11import { useForm , useStore } from "@tanstack/react-form" ;
22import { useMutation } from "@tanstack/react-query" ;
33import { Loader2Icon , SparklesIcon , TagsIcon } from "lucide-react" ;
4- import { useEffect , useState } from "react" ;
4+ import { useEffect , useRef , useState } from "react" ;
55import { toast } from "sonner" ;
66import { z } from "zod" ;
77import { Badge } from "@/components/ui/badge" ;
@@ -15,13 +15,6 @@ import {
1515 FieldLabel ,
1616} from "@/components/ui/field" ;
1717import { InputBadge } from "@/components/ui/input-badge" ;
18- import {
19- Select ,
20- SelectContent ,
21- SelectItem ,
22- SelectTrigger ,
23- SelectValue ,
24- } from "@/components/ui/select" ;
2518import { Textarea } from "@/components/ui/textarea" ;
2619import { useMemoryMutations , useTopUsedTags } from "@/hooks/use-memories" ;
2720import { getCategorizationService } from "@/lib/ai/categorization-service" ;
@@ -63,6 +56,10 @@ export function EntryForm({
6356 onCancel,
6457} : EntryFormProps ) {
6558 const isPreviewMode = layout === "preview" ;
59+ const formRef = useRef < HTMLFormElement > ( null ) ;
60+ const [ portalContainer , setPortalContainer ] = useState < HTMLElement | null > (
61+ null ,
62+ ) ;
6663 const [ selectedProvider , setSelectedProvider ] = useState <
6764 AIProvider | undefined
6865 > ( ) ;
@@ -254,6 +251,17 @@ export function EntryForm({
254251 } ;
255252 } , [ ] ) ;
256253
254+ useEffect ( ( ) => {
255+ const formElement = formRef . current ;
256+
257+ if ( isPreviewMode && formElement ) {
258+ setPortalContainer ( formElement ) ;
259+ return ;
260+ }
261+
262+ setPortalContainer ( null ) ;
263+ } , [ isPreviewMode ] ) ;
264+
257265 useEffect ( ( ) => {
258266 const handleKeyDown = ( e : KeyboardEvent ) => {
259267 if ( ( e . metaKey || e . ctrlKey ) && e . key === "Enter" ) {
@@ -313,6 +321,7 @@ export function EntryForm({
313321
314322 return (
315323 < form
324+ ref = { formRef }
316325 onSubmit = { ( e ) => {
317326 e . preventDefault ( ) ;
318327 form . handleSubmit ( ) ;
@@ -446,43 +455,18 @@ export function EntryForm({
446455 < SparklesIcon className = "size-3 animate-pulse" />
447456 ) }
448457 </ FieldLabel >
449- { ! isPreviewMode ? (
450- < Combobox
451- id = { field . name }
452- name = { field . name }
453- value = { field . state . value }
454- onValueChange = { field . handleChange }
455- options = { categoryOptions }
456- placeholder = "Select a category"
457- searchPlaceholder = "Search categories..."
458- emptyText = "No category found."
459- aria-invalid = { isInvalid }
460- />
461- ) : (
462- < Select
463- value = { field . state . value }
464- onValueChange = { field . handleChange }
465- >
466- < SelectTrigger
467- id = { field . name }
468- onBlur = { field . handleBlur }
469- aria-invalid = { isInvalid }
470- aria-describedby = {
471- isInvalid ? `${ field . name } -error` : undefined
472- }
473- className = "w-full"
474- >
475- < SelectValue placeholder = "Select a category" />
476- </ SelectTrigger >
477- < SelectContent >
478- { categoryOptions . map ( ( option ) => (
479- < SelectItem key = { option . value } value = { option . value } >
480- { option . label }
481- </ SelectItem >
482- ) ) }
483- </ SelectContent >
484- </ Select >
485- ) }
458+ < Combobox
459+ id = { field . name }
460+ name = { field . name }
461+ value = { field . state . value }
462+ onValueChange = { field . handleChange }
463+ options = { categoryOptions }
464+ placeholder = "Select a category"
465+ searchPlaceholder = "Search categories..."
466+ emptyText = "No category found."
467+ portalContainer = { portalContainer }
468+ aria-invalid = { isInvalid }
469+ />
486470 { isInvalid && (
487471 < FieldError
488472 id = { `${ field . name } -error` }
0 commit comments