import { useEffect, useRef } from "preact/hooks"; import TextArea, { DEFAULT_LINE_HEIGHT, DEFAULT_TEXT_AREA_PADDING, TextAreaProps, TEXT_AREA_BORDER_WIDTH, } from "../components/ui/TextArea"; import { internalSubscribe } from "./eventEmitter"; import { isTouchscreenDevice } from "./isTouchscreenDevice"; type TextAreaAutoSizeProps = Omit< JSX.HTMLAttributes, "style" | "value" > & TextAreaProps & { forceFocus?: boolean; autoFocus?: boolean; minHeight?: number; maxRows?: number; value: string; id?: string; }; export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { const { autoFocus, minHeight, maxRows, value, padding, lineHeight, hideBorder, forceFocus, children, as, onChange, ...textAreaProps } = props; const line = lineHeight ?? DEFAULT_LINE_HEIGHT; const heightPadding = ((padding ?? DEFAULT_TEXT_AREA_PADDING) + (hideBorder ? 0 : TEXT_AREA_BORDER_WIDTH)) * 2; const height = Math.max( Math.min(value.split("\n").length, maxRows ?? Infinity) * line + heightPadding, minHeight ?? 0, ); const ref = useRef(); useEffect(() => { if (isTouchscreenDevice) return; autoFocus && ref.current.focus(); }, [value]); const inputSelected = () => ["TEXTAREA", "INPUT"].includes(document.activeElement?.nodeName ?? ""); useEffect(() => { if (forceFocus) { ref.current.focus(); } if (isTouchscreenDevice) return; if (autoFocus && !inputSelected()) { ref.current.focus(); } // ? if you are wondering what this is // ? it is a quick and dirty hack to fix // ? value not setting correctly // ? I have no clue what's going on ref.current.value = value; if (!autoFocus) return; function keyDown(e: KeyboardEvent) { if ((e.ctrlKey && e.key !== "v") || e.altKey || e.metaKey) return; if (e.key.length !== 1) return; if (ref && !inputSelected()) { ref.current.focus(); } } document.body.addEventListener("keydown", keyDown); return () => document.body.removeEventListener("keydown", keyDown); }, [ref]); useEffect(() => { function focus(id: string) { if (id === props.id) { ref.current.focus(); } } return internalSubscribe("TextArea", "focus", focus); }, [ref]); return (