make WorkflowBlockInputArea a 'hybrid sync component', rather than a … (#3232)

This commit is contained in:
Jonathan Dobson
2025-08-19 12:08:30 -04:00
committed by GitHub
parent 273d0b0edf
commit fa978bccd7

View File

@@ -4,7 +4,7 @@ import { AutoResizingTextarea } from "./AutoResizingTextarea/AutoResizingTextare
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { WorkflowBlockParameterSelect } from "@/routes/workflows/editor/nodes/WorkflowBlockParameterSelect"; import { WorkflowBlockParameterSelect } from "@/routes/workflows/editor/nodes/WorkflowBlockParameterSelect";
import { useWorkflowTitleStore } from "@/store/WorkflowTitleStore"; import { useWorkflowTitleStore } from "@/store/WorkflowTitleStore";
import { useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
type Props = Omit< type Props = Omit<
React.ComponentProps<typeof AutoResizingTextarea>, React.ComponentProps<typeof AutoResizingTextarea>,
@@ -18,25 +18,26 @@ type Props = Omit<
function WorkflowBlockInputTextarea(props: Props) { function WorkflowBlockInputTextarea(props: Props) {
const { maybeAcceptTitle, maybeWriteTitle } = useWorkflowTitleStore(); const { maybeAcceptTitle, maybeWriteTitle } = useWorkflowTitleStore();
const { nodeId, onChange, canWriteTitle = false, ...textAreaProps } = props; const { nodeId, onChange, canWriteTitle = false, ...textAreaProps } = props;
const [internalValue, setInternalValue] = useState(props.value ?? "");
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
const [cursorPosition, setCursorPosition] = useState<{ const [cursorPosition, setCursorPosition] = useState<{
start: number; start: number;
end: number; end: number;
} | null>(null); } | null>(null);
const handleOnBlur = () => { useEffect(() => {
setInternalValue(props.value ?? "");
}, [props.value]);
const doOnChange = (value: string) => {
onChange(value);
maybeWriteTitle(value);
if (canWriteTitle) { if (canWriteTitle) {
maybeAcceptTitle(); maybeAcceptTitle();
} }
}; };
const handleOnChange = (value: string) => {
onChange(value);
if (canWriteTitle) {
maybeWriteTitle(value);
}
};
const handleTextareaSelect = () => { const handleTextareaSelect = () => {
if (textareaRef.current) { if (textareaRef.current) {
setCursorPosition({ setCursorPosition({
@@ -55,7 +56,7 @@ function WorkflowBlockInputTextarea(props: Props) {
const newValue = const newValue =
value.substring(0, start) + parameterText + value.substring(end); value.substring(0, start) + parameterText + value.substring(end);
handleOnChange(newValue); doOnChange(newValue);
setTimeout(() => { setTimeout(() => {
if (textareaRef.current) { if (textareaRef.current) {
@@ -65,7 +66,7 @@ function WorkflowBlockInputTextarea(props: Props) {
} }
}, 0); }, 0);
} else { } else {
handleOnChange(`${value}${parameterText}`); doOnChange(`${value}${parameterText}`);
} }
}; };
@@ -73,10 +74,13 @@ function WorkflowBlockInputTextarea(props: Props) {
<div className="relative"> <div className="relative">
<AutoResizingTextarea <AutoResizingTextarea
{...textAreaProps} {...textAreaProps}
value={internalValue}
ref={textareaRef} ref={textareaRef}
onBlur={handleOnBlur} onBlur={(event) => {
doOnChange(event.target.value);
}}
onChange={(event) => { onChange={(event) => {
handleOnChange(event.target.value); setInternalValue(event.target.value);
handleTextareaSelect(); handleTextareaSelect();
}} }}
onClick={handleTextareaSelect} onClick={handleTextareaSelect}