fix DictAsYamlField feedback loop

formData sync overwrites user input, fix was to skip external sync while the field is focused
This commit is contained in:
Josh Hawkins 2026-04-04 21:55:27 -05:00
parent 9ba81d6dc8
commit f3a9bf7763

View File

@ -2,7 +2,7 @@ import type { FieldPathList, FieldProps } from "@rjsf/utils";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
function formatYaml(value: unknown): string { function formatYaml(value: unknown): string {
if ( if (
@ -54,10 +54,14 @@ export function DictAsYamlField(props: FieldProps) {
const [text, setText] = useState(() => formatYaml(formData)); const [text, setText] = useState(() => formatYaml(formData));
const [error, setError] = useState<string>(); const [error, setError] = useState<string>();
const focusedRef = useRef(false);
useEffect(() => { useEffect(() => {
setText(formatYaml(formData)); // Only sync from external formData changes, not our own onChange
setError(undefined); if (!focusedRef.current) {
setText(formatYaml(formData));
setError(undefined);
}
}, [formData]); }, [formData]);
const handleChange = useCallback( const handleChange = useCallback(
@ -73,8 +77,13 @@ export function DictAsYamlField(props: FieldProps) {
[onChange, fieldPath], [onChange, fieldPath],
); );
const handleFocus = useCallback(() => {
focusedRef.current = true;
}, []);
const handleBlur = useCallback( const handleBlur = useCallback(
(_e: React.FocusEvent<HTMLTextAreaElement>) => { (_e: React.FocusEvent<HTMLTextAreaElement>) => {
focusedRef.current = false;
// Reformat on blur if valid // Reformat on blur if valid
const { value } = parseYaml(text); const { value } = parseYaml(text);
if (value !== undefined) { if (value !== undefined) {
@ -101,6 +110,7 @@ export function DictAsYamlField(props: FieldProps) {
placeholder={"key: value"} placeholder={"key: value"}
rows={Math.max(3, text.split("\n").length + 1)} rows={Math.max(3, text.split("\n").length + 1)}
onChange={handleChange} onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur} onBlur={handleBlur}
/> />
{error && <p className="text-xs text-destructive">{error}</p>} {error && <p className="text-xs text-destructive">{error}</p>}