fix(wand): improved flickering for invalid JSON icon while streaming (#2868)

This commit is contained in:
Waleed
2026-01-17 12:43:22 -08:00
committed by GitHub
parent 8740566f6a
commit f6960a4bd4
2 changed files with 30 additions and 40 deletions

View File

@@ -307,25 +307,18 @@ export function Code({
? getDefaultValueString()
: storeValue
const lastValidationStatus = useRef<boolean>(true)
useEffect(() => {
if (!onValidationChange) return
const nextStatus = shouldValidateJson ? isValidJson : true
if (lastValidationStatus.current === nextStatus) {
return
}
const isValid = !shouldValidateJson || isValidJson
lastValidationStatus.current = nextStatus
if (!shouldValidateJson) {
onValidationChange(nextStatus)
if (isValid) {
onValidationChange(true)
return
}
const timeoutId = setTimeout(() => {
onValidationChange(nextStatus)
onValidationChange(false)
}, 150)
return () => clearTimeout(timeoutId)
@@ -337,7 +330,7 @@ export function Code({
}
handleStreamChunkRef.current = (chunk: string) => {
setCode((prev) => prev + chunk)
setCode((prev: string) => prev + chunk)
}
handleGeneratedContentRef.current = (generatedCode: string) => {
@@ -434,12 +427,12 @@ export function Code({
`
document.body.appendChild(tempContainer)
lines.forEach((line) => {
lines.forEach((line: string) => {
const lineDiv = document.createElement('div')
if (line.includes('<') && line.includes('>')) {
const parts = line.split(/(<[^>]+>)/g)
parts.forEach((part) => {
parts.forEach((part: string) => {
const span = document.createElement('span')
span.textContent = part
lineDiv.appendChild(span)
@@ -472,7 +465,6 @@ export function Code({
}
}, [code])
// Event Handlers
/**
* Handles drag-and-drop events for inserting reference tags into the code editor.
* @param e - The drag event
@@ -500,7 +492,6 @@ export function Code({
textarea.selectionStart = newCursorPosition
textarea.selectionEnd = newCursorPosition
// Show tag dropdown after cursor is positioned
setShowTags(true)
if (data.connectionData?.sourceBlockId) {
setActiveSourceBlockId(data.connectionData.sourceBlockId)
@@ -559,7 +550,6 @@ export function Code({
}
}
// Helper Functions
/**
* Determines whether a `<...>` segment should be highlighted as a reference.
* @param part - The code segment to check
@@ -596,7 +586,6 @@ export function Code({
return accessiblePrefixes.has(normalizedPrefix)
}
// Expose wand control handlers to parent via ref
useImperativeHandle(
wandControlRef,
() => ({
@@ -617,7 +606,7 @@ export function Code({
const numbers: ReactElement[] = []
let lineNumber = 1
visualLineHeights.forEach((height) => {
visualLineHeights.forEach((height: number) => {
const isActive = lineNumber === activeLineNumber
numbers.push(
<div
@@ -724,7 +713,7 @@ export function Code({
<Editor
value={code}
onValueChange={(newCode) => {
onValueChange={(newCode: string) => {
if (!isAiStreaming && !isPreview && !disabled && !readOnly) {
hasEditedSinceFocusRef.current = true
setCode(newCode)
@@ -761,7 +750,6 @@ export function Code({
}}
onFocus={() => {
hasEditedSinceFocusRef.current = false
// Show tag dropdown on focus when code is empty
if (!isPreview && !disabled && !readOnly && code.trim() === '') {
setShowTags(true)
setCursorPosition(0)

View File

@@ -207,21 +207,21 @@ const renderLabel = (
<Label className='flex items-center gap-[6px] whitespace-nowrap'>
{config.title}
{required && <span className='ml-0.5'>*</span>}
{config.type === 'code' && config.language === 'json' && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<AlertTriangle
className={cn(
'h-4 w-4 cursor-pointer text-destructive',
!isValidJson ? 'opacity-100' : 'opacity-0'
)}
/>
</Tooltip.Trigger>
<Tooltip.Content side='top'>
<p>Invalid JSON</p>
</Tooltip.Content>
</Tooltip.Root>
)}
{config.type === 'code' &&
config.language === 'json' &&
!isValidJson &&
!wandState?.isStreaming && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<span className='inline-flex'>
<AlertTriangle className='h-3 w-3 flex-shrink-0 cursor-pointer text-destructive' />
</span>
</Tooltip.Trigger>
<Tooltip.Content side='top'>
<p>Invalid JSON</p>
</Tooltip.Content>
</Tooltip.Root>
)}
</Label>
<div className='flex items-center gap-[6px]'>
{showWand && (
@@ -239,9 +239,11 @@ const renderLabel = (
<Input
ref={wandState.searchInputRef}
value={wandState.isStreaming ? 'Generating...' : wandState.searchQuery}
onChange={(e) => wandState.onSearchChange(e.target.value)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
wandState.onSearchChange(e.target.value)
}
onBlur={wandState.onSearchBlur}
onKeyDown={(e) => {
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (
e.key === 'Enter' &&
wandState.searchQuery.trim() &&
@@ -262,11 +264,11 @@ const renderLabel = (
<Button
variant='tertiary'
disabled={!wandState.searchQuery.trim() || wandState.isStreaming}
onMouseDown={(e) => {
onMouseDown={(e: React.MouseEvent) => {
e.preventDefault()
e.stopPropagation()
}}
onClick={(e) => {
onClick={(e: React.MouseEvent) => {
e.stopPropagation()
wandState.onSearchSubmit()
}}