a tool for shared writing and social publishing
1import {
2 forwardRef,
3 useEffect,
4 useImperativeHandle,
5 useRef,
6 useState,
7} from "react";
8import styles from "./textarea-styles.module.css";
9
10export type AutosizeTextareaProps = React.DetailedHTMLProps<
11 React.TextareaHTMLAttributes<HTMLTextAreaElement>,
12 HTMLTextAreaElement
13> & { noWrap?: boolean };
14export const AutosizeTextarea = forwardRef<
15 HTMLTextAreaElement,
16 AutosizeTextareaProps
17>((props: AutosizeTextareaProps & { noWrap?: boolean }, ref) => {
18 let textarea = useRef<HTMLTextAreaElement | null>(null);
19 let { noWrap, ...rest } = props;
20 useImperativeHandle(ref, () => textarea.current as HTMLTextAreaElement);
21
22 return (
23 <div
24 className={`${styles["grow-wrap"]} ${props.className} ${noWrap ? styles["no-wrap"] : ""}`}
25 data-replicated-value={props.value}
26 style={props.style}
27 >
28 <textarea
29 rows={1}
30 {...rest}
31 ref={textarea}
32 className={`placeholder:text-tertiary bg-transparent ${props.className}`}
33 />
34 </div>
35 );
36});
37
38export const AsyncValueAutosizeTextarea = forwardRef<
39 HTMLTextAreaElement,
40 AutosizeTextareaProps
41>((props: AutosizeTextareaProps, ref) => {
42 let [intermediateState, setIntermediateState] = useState(
43 props.value as string,
44 );
45
46 useEffect(() => {
47 setIntermediateState(props.value as string);
48 }, [props.value]);
49
50 return (
51 <AutosizeTextarea
52 {...props}
53 ref={ref}
54 value={intermediateState}
55 onChange={async (e) => {
56 if (!props.onChange) return;
57 setIntermediateState(e.currentTarget.value);
58 await Promise.all([props.onChange(e)]);
59 }}
60 />
61 );
62});
63
64AutosizeTextarea.displayName = "Textarea";