11import { useCallback , useRef } from 'react'
2- import { generateId } from '@sim/utils/id'
32import { Plus } from 'lucide-react'
43import { Trash } from '@/components/emcn/icons/trash'
54import 'prismjs/components/prism-json'
@@ -21,6 +20,7 @@ import {
2120} from '@/components/emcn'
2221import { cn } from '@/lib/core/utils/cn'
2322import { handleKeyboardActivation } from '@/lib/core/utils/keyboard'
23+ import { createDefaultInputFormatField } from '@/lib/workflows/input-format'
2424import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
2525import { TagDropdown } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown'
2626import { getActiveWorkflowSearchHighlight } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/workflow-search-highlight'
@@ -74,18 +74,6 @@ const BOOLEAN_OPTIONS: ComboboxOption[] = [
7474 { label : 'false' , value : 'false' } ,
7575]
7676
77- /**
78- * Creates a new field with default values
79- */
80- const createDefaultField = ( ) : Field => ( {
81- id : generateId ( ) ,
82- name : '' ,
83- type : 'string' ,
84- value : '' ,
85- description : '' ,
86- collapsed : false ,
87- } )
88-
8977/**
9078 * Validates and sanitizes field names by removing control characters and quotes
9179 */
@@ -127,8 +115,17 @@ export function FieldFormat({
127115 disabled,
128116 } )
129117
118+ /**
119+ * Stable fallback field used while the store value is still empty (e.g. a
120+ * newly added block). Caching it in a ref keeps the field id constant across
121+ * renders, so the inputs don't remount on each keystroke and edits commit to
122+ * the same id instead of a freshly generated one.
123+ */
124+ const fallbackFieldRef = useRef < Field | null > ( null )
125+ const fallbackField = ( fallbackFieldRef . current ??= createDefaultInputFormatField ( ) )
126+
130127 const value = isPreview ? previewValue : storeValue
131- const fields : Field [ ] = Array . isArray ( value ) && value . length > 0 ? value : [ createDefaultField ( ) ]
128+ const fields : Field [ ] = Array . isArray ( value ) && value . length > 0 ? value : [ fallbackField ]
132129 const isReadOnly = isPreview || disabled
133130
134131 const renderFieldLabel = ( label : string ) => < Label > { label } </ Label >
@@ -138,7 +135,7 @@ export function FieldFormat({
138135 */
139136 const addField = ( ) => {
140137 if ( isReadOnly ) return
141- setStoreValue ( [ ...fields , createDefaultField ( ) ] )
138+ setStoreValue ( [ ...fields , createDefaultInputFormatField ( ) ] )
142139 }
143140
144141 /**
@@ -148,15 +145,19 @@ export function FieldFormat({
148145 if ( isReadOnly ) return
149146
150147 if ( fields . length === 1 ) {
151- setStoreValue ( [ createDefaultField ( ) ] )
148+ setStoreValue ( [ createDefaultInputFormatField ( ) ] )
152149 return
153150 }
154151
155152 setStoreValue ( fields . filter ( ( field ) => field . id !== id ) )
156153 }
157154
158- const storeValueRef = useRef ( storeValue )
159- storeValueRef . current = storeValue
155+ /**
156+ * Mirrors the rendered fields (store value or stable fallback) so updateField
157+ * always commits against the same ids the UI is currently showing.
158+ */
159+ const fieldsRef = useRef ( fields )
160+ fieldsRef . current = fields
160161
161162 const isReadOnlyRef = useRef ( isReadOnly )
162163 isReadOnlyRef . current = isReadOnly
@@ -173,14 +174,8 @@ export function FieldFormat({
173174 ? validateFieldName ( fieldValue )
174175 : fieldValue
175176
176- const currentStoreValue = storeValueRef . current
177- const currentFields : Field [ ] =
178- Array . isArray ( currentStoreValue ) && currentStoreValue . length > 0
179- ? currentStoreValue
180- : [ createDefaultField ( ) ]
181-
182177 setStoreValueRef . current (
183- currentFields . map ( ( f ) => ( f . id === id ? { ...f , [ fieldKey ] : updatedValue } : f ) )
178+ fieldsRef . current . map ( ( f ) => ( f . id === id ? { ...f , [ fieldKey ] : updatedValue } : f ) )
184179 )
185180 } ,
186181 [ ]
0 commit comments