From cf51d288ebc233c32668f8064646609dc98154ff Mon Sep 17 00:00:00 2001 From: graphemecluster Date: Mon, 16 Dec 2024 04:29:48 +0800 Subject: [PATCH] Resize article input box automatically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manually expanding the input box is no longer needed and the vertical resize handle is now useless (it can’t be dragged), thus the `resize` property is reverted to `none`. --- src/Components/Main.tsx | 67 ++++++++++++++++++++++++--------- src/Components/SchemaEditor.tsx | 22 +++++++---- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/Components/Main.tsx b/src/Components/Main.tsx index ea1db89..8f555ae 100644 --- a/src/Components/Main.tsx +++ b/src/Components/Main.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useReducer, useRef, useState } from "react"; +import { useCallback, useEffect, useLayoutEffect, useReducer, useRef, useState } from "react"; import { createPortal } from "react-dom"; import styled from "@emotion/styled"; @@ -23,8 +23,10 @@ const dummyOutput = document.createElement("output"); const ArticleInput = styled.textarea` line-height: 1.6; - resize: block; + resize: none; width: 100%; + flex: 1; + overflow: hidden; `; const OutputContainer = styled.dialog` transform: translateY(10%); @@ -216,6 +218,37 @@ export default function Main({ evaluateHandlerRef }: { evaluateHandlerRef: Mutab }); }, []); + const [articleInput, setArticleInput] = useState(null); + useLayoutEffect(() => { + if (!articleInput) return; + const textArea = articleInput; + const container = textArea.parentElement!; + function resizeTextArea() { + const scrollTop = container.scrollTop; + // First measure without a scrollbar + textArea.style.minHeight = ""; + textArea.style.flex = "unset"; + const computedStyle = getComputedStyle(textArea); + const borderHeight = parseFloat(computedStyle.borderTopWidth) + parseFloat(computedStyle.borderBottomWidth); + textArea.style.minHeight = `max(9em, ${textArea.scrollHeight + borderHeight}px)`; + if (textArea.scrollHeight > textArea.getBoundingClientRect().height) { + // Remeasure if the input doesn’t actually fit due to the addition of scrollbar + textArea.style.minHeight = ""; + container.style.overflowY = "scroll"; + textArea.style.minHeight = `max(9em, ${textArea.scrollHeight + borderHeight}px)`; + container.style.overflowY = ""; + } + textArea.style.flex = ""; + container.scrollTop = scrollTop; + } + resizeTextArea(); + const resizeObserver = new ResizeObserver(resizeTextArea); + resizeObserver.observe(container); + return () => { + resizeObserver.disconnect(); + }; + }, [article, articleInput]); + const resetArticle = useCallback(async () => { if ( !article || @@ -245,7 +278,7 @@ export default function Main({ evaluateHandlerRef }: { evaluateHandlerRef: Mutab setState={setState} commonOptions={ <> -

+