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:
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user