From 0f07886d982f22fc9a3b5b6dc984fdc203f57f66 Mon Sep 17 00:00:00 2001 From: Sarah Rietkerk Date: Fri, 15 Mar 2024 17:56:49 -0700 Subject: [PATCH 1/5] notes area auto resizing on enter, more text entered --- react-common/components/controls/Textarea.tsx | 9 +++++++ .../src/components/DebouncedTextarea.tsx | 25 ++++++++++++++++++- .../styling/EvalResultDisplay.module.scss | 3 +-- teachertool/src/style.overrides/Textarea.scss | 1 - 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/react-common/components/controls/Textarea.tsx b/react-common/components/controls/Textarea.tsx index 311be961b9d9..cd23112e0cf4 100644 --- a/react-common/components/controls/Textarea.tsx +++ b/react-common/components/controls/Textarea.tsx @@ -14,6 +14,8 @@ export interface TextareaProps extends ControlProps { readOnly?: boolean; resize?: "both" | "horizontal" | "vertical"; wrap?: "hard" | "soft" | "off"; + autoResize?: boolean; + resizeRef?: React.RefObject; onChange?: (newValue: string) => void; onEnterKey?: (value: string) => void; @@ -38,6 +40,8 @@ export const Textarea = (props: TextareaProps) => { readOnly, resize, wrap, + autoResize, + resizeRef, onChange, onEnterKey } = props; @@ -57,6 +61,10 @@ export const Textarea = (props: TextareaProps) => { if (onChange) { onChange(newValue); } + if (autoResize && resizeRef.current) { + resizeRef.current.style.height = "1px"; + resizeRef.current.style.height = `${25 + resizeRef.current.scrollHeight}px`; + } } const enterKeyHandler = (e: React.KeyboardEvent) => { @@ -90,6 +98,7 @@ export const Textarea = (props: TextareaProps) => { minLength={minLength} wrap={wrap} readOnly={!!readOnly} + ref={resizeRef} onChange={changeHandler} onKeyDown={enterKeyHandler} autoComplete={autoComplete ? "" : "off"} diff --git a/teachertool/src/components/DebouncedTextarea.tsx b/teachertool/src/components/DebouncedTextarea.tsx index 4166b074af06..5e1d48795a4e 100644 --- a/teachertool/src/components/DebouncedTextarea.tsx +++ b/teachertool/src/components/DebouncedTextarea.tsx @@ -11,6 +11,8 @@ export interface DebouncedTextareaProps extends TextareaProps { export const DebouncedTextarea: React.FC = ({ intervalMs = 500, ...props }) => { const timerId = useRef(undefined); const latestValue = useRef(""); + const textareaRef = useRef(null); + const containerRef = useRef(null); const sendChange = () => { if (props.onChange) { @@ -21,11 +23,28 @@ export const DebouncedTextarea: React.FC = ({ intervalMs // If the timer is pending and the component unmounts, // clear the timer and fire the onChange event immediately. useEffect(() => { + const resizeObserver = new ResizeObserver(() => { + window.requestAnimationFrame(() => { + if (containerRef.current) { + containerRef.current.style.height = "1px"; + containerRef.current.style.height = `${25 + containerRef.current.scrollHeight}px`; + } + }); + }); + + if (textareaRef.current) { + resizeObserver.observe(textareaRef.current); + } + return () => { if (timerId.current) { clearTimeout(timerId.current); sendChange(); } + + if (textareaRef.current) { + resizeObserver.unobserve(textareaRef.current); + } }; }, []); @@ -39,5 +58,9 @@ export const DebouncedTextarea: React.FC = ({ intervalMs timerId.current = setTimeout(sendChange, intervalMs); }; - return