fix: insert parameters at cursor position (#2867)

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: Suchintan <suchintan@users.noreply.github.com>
Co-authored-by: Jonathan Dobson <jon.m.dobson@gmail.com>
This commit is contained in:
Nate
2025-07-09 18:39:52 -04:00
committed by GitHub
parent af7b862e02
commit ae816d5227
2 changed files with 116 additions and 39 deletions

View File

@@ -1,5 +1,12 @@
import { ChangeEventHandler, useEffect, useLayoutEffect, useRef } from "react";
import { Textarea } from "@/components/ui/textarea";
import type { ChangeEventHandler, HTMLAttributes } from "react";
import {
forwardRef,
useEffect,
useLayoutEffect,
useRef,
useCallback,
} from "react";
import { cn } from "@/util/utils";
type Props = {
@@ -8,44 +15,73 @@ type Props = {
className?: string;
readOnly?: boolean;
placeholder?: string;
};
onClick?: React.MouseEventHandler<HTMLTextAreaElement>;
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>;
onSelect?: React.ReactEventHandler<HTMLTextAreaElement>;
} & Omit<HTMLAttributes<HTMLTextAreaElement>, "onChange" | "value">;
function AutoResizingTextarea({
value,
onChange,
className,
readOnly,
placeholder,
}: Props) {
const ref = useRef<HTMLTextAreaElement>(null);
const AutoResizingTextarea = forwardRef<HTMLTextAreaElement, Props>(
(
{
value,
onChange,
className,
readOnly,
placeholder,
onClick,
onKeyUp,
onSelect,
...restProps
},
forwardedRef,
) => {
const innerRef = useRef<HTMLTextAreaElement | null>(null);
const getTextarea = useCallback(() => innerRef.current, []);
useLayoutEffect(() => {
// size the textarea correctly on first render
if (!ref.current) {
return;
}
ref.current.style.height = `${ref.current.scrollHeight + 2}px`;
}, []);
const setRefs = (element: HTMLTextAreaElement | null) => {
innerRef.current = element;
useEffect(() => {
if (!ref.current) {
return;
}
ref.current.style.height = "auto";
ref.current.style.height = `${ref.current.scrollHeight + 2}px`;
}, [value]);
// Forward to external ref
if (typeof forwardedRef === "function") {
forwardedRef(element);
} else if (forwardedRef) {
forwardedRef.current = element;
}
};
return (
<Textarea
value={value}
onChange={onChange}
readOnly={readOnly}
placeholder={placeholder}
ref={ref}
rows={1}
className={cn("min-h-0 resize-none overflow-y-hidden", className)}
/>
);
}
useLayoutEffect(() => {
const textareaElement = getTextarea();
if (!textareaElement) {
return;
}
textareaElement.style.height = `${textareaElement.scrollHeight + 2}px`;
}, [getTextarea]);
useEffect(() => {
const textareaElement = getTextarea();
if (!textareaElement) {
return;
}
textareaElement.style.height = "auto";
textareaElement.style.height = `${textareaElement.scrollHeight + 2}px`;
}, [getTextarea, value]);
return (
<Textarea
value={value}
onChange={onChange}
readOnly={readOnly}
placeholder={placeholder}
onClick={onClick}
onKeyUp={onKeyUp}
onSelect={onSelect}
ref={setRefs}
rows={1}
className={cn("min-h-0 resize-none overflow-y-hidden", className)}
{...restProps}
/>
);
},
);
export { AutoResizingTextarea };