@@ -102,6 +102,7 @@ export function VariablesInput({
102102 const [ activeSourceBlockId , setActiveSourceBlockId ] = useState < string | null > ( null )
103103 const valueInputRefs = useRef < Record < string , HTMLInputElement | HTMLTextAreaElement > > ( { } )
104104 const overlayRefs = useRef < Record < string , HTMLDivElement > > ( { } )
105+ const editorContainerRefs = useRef < Record < string , HTMLDivElement | null > > ( { } )
105106 const [ dragHighlight , setDragHighlight ] = useState < Record < string , boolean > > ( { } )
106107 const [ collapsedAssignments , setCollapsedAssignments ] = useState < Record < string , boolean > > ( { } )
107108
@@ -190,6 +191,26 @@ export function VariablesInput({
190191 if ( ! editorValueChangeHandlersRef . current [ assignmentId ] ) {
191192 editorValueChangeHandlersRef . current [ assignmentId ] = ( newValue : string ) => {
192193 updateAssignmentRef . current ( assignmentId , { value : newValue } )
194+
195+ const container = editorContainerRefs . current [ assignmentId ]
196+ const textarea = container ?. querySelector ( 'textarea' )
197+ if ( textarea ) {
198+ const pos = textarea . selectionStart
199+ setCursorPosition ( pos )
200+ setActiveFieldId ( assignmentId )
201+
202+ const tagTrigger = checkTagTrigger ( newValue , pos )
203+ setShowTags ( tagTrigger . show )
204+ if ( tagTrigger . show ) {
205+ const textBeforeCursor = newValue . slice ( 0 , pos )
206+ const lastOpenBracket = textBeforeCursor . lastIndexOf ( '<' )
207+ const tagContent = textBeforeCursor . slice ( lastOpenBracket + 1 )
208+ const dotIndex = tagContent . indexOf ( '.' )
209+ setActiveSourceBlockId ( dotIndex > 0 ? tagContent . slice ( 0 , dotIndex ) : null )
210+ } else {
211+ setActiveSourceBlockId ( null )
212+ }
213+ }
193214 }
194215 }
195216 return editorValueChangeHandlersRef . current [ assignmentId ]
@@ -215,16 +236,27 @@ export function VariablesInput({
215236 const assignment = assignments . find ( ( a ) => a . id === activeFieldId )
216237 const originalValue = assignment ?. value || ''
217238 const textAfterCursor = originalValue . slice ( cursorPosition )
239+ const isCodeEditor = assignment ?. type === 'object' || assignment ?. type === 'array'
218240
219241 updateAssignment ( activeFieldId , { value : newValue } )
220242 setShowTags ( false )
221243
222244 setTimeout ( ( ) => {
223- const inputEl = valueInputRefs . current [ activeFieldId ]
224- if ( inputEl ) {
225- inputEl . focus ( )
226- const newCursorPos = newValue . length - textAfterCursor . length
227- inputEl . setSelectionRange ( newCursorPos , newCursorPos )
245+ const newCursorPos = newValue . length - textAfterCursor . length
246+ if ( isCodeEditor ) {
247+ const container = editorContainerRefs . current [ activeFieldId ]
248+ const textarea = container ?. querySelector ( 'textarea' )
249+ if ( textarea ) {
250+ textarea . focus ( )
251+ textarea . selectionStart = newCursorPos
252+ textarea . selectionEnd = newCursorPos
253+ }
254+ } else {
255+ const inputEl = valueInputRefs . current [ activeFieldId ]
256+ if ( inputEl ) {
257+ inputEl . focus ( )
258+ inputEl . setSelectionRange ( newCursorPos , newCursorPos )
259+ }
228260 }
229261 } , 10 )
230262 }
@@ -298,6 +330,39 @@ export function VariablesInput({
298330 setDragHighlight ( ( prev ) => ( { ...prev , [ assignmentId ] : false } ) )
299331 }
300332
333+ const handleEditorDrop = ( e : React . DragEvent , assignmentId : string ) => {
334+ if ( isReadOnly ) return
335+ e . preventDefault ( )
336+ try {
337+ const data = JSON . parse ( e . dataTransfer . getData ( 'application/json' ) )
338+ if ( data . type !== 'connectionBlock' ) return
339+
340+ const container = editorContainerRefs . current [ assignmentId ]
341+ const textarea = container ?. querySelector ( 'textarea' )
342+ const assignment = assignments . find ( ( a ) => a . id === assignmentId )
343+ const currentValue = assignment ?. value || ''
344+ const dropPosition = textarea ?. selectionStart ?? currentValue . length
345+ const newValue = `${ currentValue . slice ( 0 , dropPosition ) } <${ currentValue . slice ( dropPosition ) } `
346+
347+ updateAssignment ( assignmentId , { value : newValue } )
348+ setActiveFieldId ( assignmentId )
349+ setCursorPosition ( dropPosition + 1 )
350+
351+ if ( data . connectionData ?. sourceBlockId ) {
352+ setActiveSourceBlockId ( data . connectionData . sourceBlockId )
353+ }
354+
355+ setTimeout ( ( ) => {
356+ if ( textarea ) {
357+ textarea . focus ( )
358+ textarea . selectionStart = dropPosition + 1
359+ textarea . selectionEnd = dropPosition + 1
360+ setShowTags ( true )
361+ }
362+ } , 0 )
363+ } catch { }
364+ }
365+
301366 const toggleCollapse = ( assignmentId : string ) => {
302367 setCollapsedAssignments ( ( prev ) => ( {
303368 ...prev ,
@@ -433,7 +498,11 @@ export function VariablesInput({
433498 const gutterWidth = calculateGutterWidth ( lineCount )
434499
435500 return (
436- < Code . Container className = 'min-h-[120px]' >
501+ < Code . Container
502+ className = 'min-h-[120px]'
503+ onDragOver = { ( e ) => e . preventDefault ( ) }
504+ onDrop = { ( e ) => handleEditorDrop ( e , assignment . id ) }
505+ >
437506 < Code . Gutter width = { gutterWidth } >
438507 { Array . from ( { length : lineCount } , ( _ , i ) => (
439508 < div
@@ -445,7 +514,14 @@ export function VariablesInput({
445514 </ div >
446515 ) ) }
447516 </ Code . Gutter >
448- < Code . Content paddingLeft = { `${ gutterWidth } px` } >
517+ < Code . Content
518+ paddingLeft = { `${ gutterWidth } px` }
519+ editorRef = {
520+ ( ( el : HTMLDivElement | null ) => {
521+ editorContainerRefs . current [ assignment . id ] = el
522+ } ) as unknown as React . RefObject < HTMLDivElement | null >
523+ }
524+ >
449525 < Code . Placeholder
450526 gutterWidth = { gutterWidth }
451527 show = { fieldValue . length === 0 }
@@ -461,6 +537,29 @@ export function VariablesInput({
461537 disabled = { isReadOnly }
462538 { ...getCodeEditorProps ( { disabled : isReadOnly } ) }
463539 />
540+ { showTags && activeFieldId === assignment . id && (
541+ < TagDropdown
542+ visible = { showTags }
543+ onSelect = { handleTagSelect }
544+ blockId = { blockId }
545+ activeSourceBlockId = { activeSourceBlockId }
546+ inputValue = { fieldValue }
547+ cursorPosition = { cursorPosition }
548+ onClose = { ( ) => {
549+ setShowTags ( false )
550+ setActiveSourceBlockId ( null )
551+ } }
552+ inputRef = {
553+ {
554+ current :
555+ ( editorContainerRefs . current [
556+ assignment . id
557+ ] ?. querySelector ( 'textarea' ) as HTMLTextAreaElement ) ??
558+ null ,
559+ } as React . RefObject < HTMLTextAreaElement | HTMLInputElement >
560+ }
561+ />
562+ ) }
464563 </ Code . Content >
465564 </ Code . Container >
466565 )
0 commit comments