mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-11 16:08:04 -05:00
fix(tag-dropdown): last char dropped bug (#945)
This commit is contained in:
committed by
GitHub
parent
a2dea384a4
commit
1a7de84c7a
@@ -158,19 +158,23 @@ export function IterationBadges({ nodeId, data, iterationType }: IterationBadges
|
||||
const handleEditorChange = useCallback(
|
||||
(value: string) => {
|
||||
if (isPreview) return
|
||||
collaborativeUpdateIterationCollection(nodeId, iterationType, value)
|
||||
|
||||
const textarea = editorContainerRef.current?.querySelector('textarea')
|
||||
// Capture cursor first to minimize staleness in dropdown logic
|
||||
const textarea = editorContainerRef.current?.querySelector(
|
||||
'textarea'
|
||||
) as HTMLTextAreaElement | null
|
||||
const cursorPos = textarea?.selectionStart ?? cursorPosition
|
||||
if (textarea) {
|
||||
textareaRef.current = textarea
|
||||
const cursorPos = textarea.selectionStart || 0
|
||||
setCursorPosition(cursorPos)
|
||||
|
||||
const triggerCheck = checkTagTrigger(value, cursorPos)
|
||||
setShowTagDropdown(triggerCheck.show)
|
||||
}
|
||||
setCursorPosition(cursorPos)
|
||||
|
||||
collaborativeUpdateIterationCollection(nodeId, iterationType, value)
|
||||
|
||||
const triggerCheck = checkTagTrigger(value, cursorPos)
|
||||
setShowTagDropdown(triggerCheck.show)
|
||||
},
|
||||
[nodeId, iterationType, collaborativeUpdateIterationCollection, isPreview]
|
||||
[nodeId, iterationType, collaborativeUpdateIterationCollection, isPreview, cursorPosition]
|
||||
)
|
||||
|
||||
// Handle tag selection
|
||||
|
||||
@@ -446,24 +446,25 @@ export function Code({
|
||||
value={code}
|
||||
onValueChange={(newCode) => {
|
||||
if (!isCollapsed && !isAiStreaming && !isPreview && !disabled) {
|
||||
// Capture cursor first to minimize staleness in dropdown logic
|
||||
const textarea = editorRef.current?.querySelector(
|
||||
'textarea'
|
||||
) as HTMLTextAreaElement | null
|
||||
const pos = textarea?.selectionStart ?? cursorPosition
|
||||
setCursorPosition(pos)
|
||||
|
||||
setCode(newCode)
|
||||
setStoreValue(newCode)
|
||||
|
||||
const textarea = editorRef.current?.querySelector('textarea')
|
||||
if (textarea) {
|
||||
const pos = textarea.selectionStart
|
||||
setCursorPosition(pos)
|
||||
|
||||
const tagTrigger = checkTagTrigger(newCode, pos)
|
||||
setShowTags(tagTrigger.show)
|
||||
if (!tagTrigger.show) {
|
||||
setActiveSourceBlockId(null)
|
||||
}
|
||||
|
||||
const envVarTrigger = checkEnvVarTrigger(newCode, pos)
|
||||
setShowEnvVars(envVarTrigger.show)
|
||||
setSearchTerm(envVarTrigger.show ? envVarTrigger.searchTerm : '')
|
||||
const tagTrigger = checkTagTrigger(newCode, pos)
|
||||
setShowTags(tagTrigger.show)
|
||||
if (!tagTrigger.show) {
|
||||
setActiveSourceBlockId(null)
|
||||
}
|
||||
|
||||
const envVarTrigger = checkEnvVarTrigger(newCode, pos)
|
||||
setShowEnvVars(envVarTrigger.show)
|
||||
setSearchTerm(envVarTrigger.show ? envVarTrigger.searchTerm : '')
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
|
||||
@@ -150,13 +150,14 @@ export function ComboBox({
|
||||
const newValue = e.target.value
|
||||
const newCursorPosition = e.target.selectionStart ?? 0
|
||||
|
||||
// Update cursor first to reduce staleness for dropdown logic
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
// Update store value immediately (allow free text)
|
||||
if (!isPreview) {
|
||||
setStoreValue(newValue)
|
||||
}
|
||||
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
// Check for environment variables trigger
|
||||
const envVarTrigger = checkEnvVarTrigger(newValue, newCursorPosition)
|
||||
setShowEnvVars(envVarTrigger.show)
|
||||
|
||||
@@ -148,6 +148,9 @@ export function LongInput({
|
||||
const newValue = e.target.value
|
||||
const newCursorPosition = e.target.selectionStart ?? 0
|
||||
|
||||
// Update cursor first to minimize state staleness for dropdown selection logic
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
// Update local content immediately
|
||||
setLocalContent(newValue)
|
||||
|
||||
@@ -158,8 +161,6 @@ export function LongInput({
|
||||
setStoreValue(newValue)
|
||||
}
|
||||
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
// Check for environment variables trigger
|
||||
const envVarTrigger = checkEnvVarTrigger(newValue, newCursorPosition)
|
||||
setShowEnvVars(envVarTrigger.show)
|
||||
|
||||
@@ -106,6 +106,9 @@ export function ShortInput({
|
||||
const newValue = e.target.value
|
||||
const newCursorPosition = e.target.selectionStart ?? 0
|
||||
|
||||
// Update cursor first to minimize state staleness for dropdown selection logic
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
if (onChange) {
|
||||
onChange(newValue)
|
||||
} else if (!isPreview) {
|
||||
@@ -113,8 +116,6 @@ export function ShortInput({
|
||||
setStoreValue(newValue)
|
||||
}
|
||||
|
||||
setCursorPosition(newCursorPosition)
|
||||
|
||||
// Check for environment variables trigger
|
||||
const envVarTrigger = checkEnvVarTrigger(newValue, newCursorPosition)
|
||||
|
||||
|
||||
@@ -869,8 +869,25 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
||||
|
||||
const handleTagSelect = useCallback(
|
||||
(tag: string, blockGroup?: BlockTagGroup) => {
|
||||
const textBeforeCursor = inputValue.slice(0, cursorPosition)
|
||||
const textAfterCursor = inputValue.slice(cursorPosition)
|
||||
// Use the live DOM selection/value if available to avoid off-by-one state
|
||||
// when users type and immediately confirm a selection.
|
||||
let liveCursor = cursorPosition
|
||||
let liveValue = inputValue
|
||||
|
||||
if (typeof window !== 'undefined' && document?.activeElement) {
|
||||
const activeEl = document.activeElement as HTMLInputElement | HTMLTextAreaElement | null
|
||||
if (activeEl && typeof activeEl.selectionStart === 'number') {
|
||||
liveCursor = activeEl.selectionStart ?? cursorPosition
|
||||
// Prefer the active element value if present. This ensures we include the most
|
||||
// recently typed character(s) that might not yet be reflected in React state.
|
||||
if (typeof (activeEl as any).value === 'string') {
|
||||
liveValue = (activeEl as any).value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const textBeforeCursor = liveValue.slice(0, liveCursor)
|
||||
const textAfterCursor = liveValue.slice(liveCursor)
|
||||
|
||||
const lastOpenBracket = textBeforeCursor.lastIndexOf('<')
|
||||
if (lastOpenBracket === -1) return
|
||||
|
||||
Reference in New Issue
Block a user