Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | import { useEffect, useRef, useState } from "react";
import styles from "./TextField.module.css";
export function MultilineTextField({
value = "",
setValue,
placeholder,
className,
id,
ariaLabel,
invalid = false,
minRows = 3,
}: {
value: string;
setValue: (value: string) => void;
placeholder?: string;
className?: string;
id?: string;
ariaLabel?: string;
invalid?: boolean;
minRows?: number;
}) {
const [readOnly, setReadOnly] = useState(true);
const [inputValue, setInputValue] = useState(value);
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
setInputValue(value);
}, [value]);
// Auto-grow logic
useEffect(() => {
const el = textareaRef.current;
if (!el) return;
el.style.height = "auto";
el.style.height = `${el.scrollHeight}px`;
}, [inputValue]);
const onCommit = () => {
setReadOnly(true);
setValue(inputValue);
};
const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
(e.target as HTMLTextAreaElement).blur();
}
};
return (
<textarea
ref={textareaRef}
rows={minRows}
placeholder={placeholder}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onFocus={() => setReadOnly(false)}
onBlur={onCommit}
onKeyDown={onKeyDown}
readOnly={readOnly}
id={id}
aria-label={ariaLabel}
className={`
${readOnly ? "drag" : "nodrag"}
flex-1
${styles.textField}
${styles.multiline}
${invalid ? styles.invalid : ""}
${className ?? ""}
`}
/>
);
}
|