From 6ca2bd11e380199629221884f10a6d1fa3eae17e Mon Sep 17 00:00:00 2001 From: rizrmd Date: Sun, 17 Mar 2024 11:06:25 -0700 Subject: [PATCH] wip fix --- comps/custom/AutoHeightTextarea.tsx | 59 +++++ comps/custom/Popover.tsx | 371 ++++++++++++++++++++++++++++ utils/pathname.ts | 4 +- 3 files changed, 432 insertions(+), 2 deletions(-) create mode 100755 comps/custom/AutoHeightTextarea.tsx create mode 100755 comps/custom/Popover.tsx diff --git a/comps/custom/AutoHeightTextarea.tsx b/comps/custom/AutoHeightTextarea.tsx new file mode 100755 index 0000000..ee0bead --- /dev/null +++ b/comps/custom/AutoHeightTextarea.tsx @@ -0,0 +1,59 @@ +import { TextareaHTMLAttributes, useCallback, useEffect, useRef } from "react"; + +export function AutoHeightTextarea({ + minRows = 1, + ...props +}: TextareaHTMLAttributes & { minRows?: number }) { + const ref = useRef(null); + + const calculateAndSetHeight = useCallback(() => { + if (!ref.current) { + return; + } + const { + borderBottomWidth, + borderTopWidth, + boxSizing, + lineHeight, + paddingBottom, + paddingTop, + } = window.getComputedStyle(ref.current); + ref.current.style.height = lineHeight; // set height temporarily to a single row to obtain scrollHeight, disregarding empty space after text (otherwise, scrollHeight would be equal to the height of the element) - this solves auto-shrinking of the textarea (it's not needed for auto-growing it) + const { scrollHeight } = ref.current; // scrollHeight = content height + padding top + padding bottom + + if (boxSizing === "border-box") { + const minHeight = + parseFloat(lineHeight) * minRows + + parseFloat(paddingTop) + + parseFloat(paddingBottom) + + parseFloat(borderTopWidth) + + parseFloat(borderBottomWidth); + const allTextHeight = + scrollHeight + + parseFloat(borderTopWidth) + + parseFloat(borderBottomWidth); + ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`; + } else if (boxSizing === "content-box") { + const minHeight = parseFloat(lineHeight) * minRows; + const allTextHeight = + scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom); + ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`; + } else { + console.error("Unknown box-sizing value."); + } + }, [minRows]); + + useEffect(() => { + calculateAndSetHeight(); + }, [calculateAndSetHeight]); + + const handleChange: React.ChangeEventHandler = (e) => { + calculateAndSetHeight(); + if (props.onChange) { + props.onChange(e); + } + }; + calculateAndSetHeight(); + + return