79 lines
1.9 KiB
TypeScript
79 lines
1.9 KiB
TypeScript
// This program has been developed by students from the bachelor Computer Science at Utrecht
|
|
// University within the Software Project course.
|
|
// © Copyright Utrecht University (Department of Information and Computing Sciences)
|
|
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 ?? ""}
|
|
`}
|
|
/>
|
|
);
|
|
}
|