From d965b20ee26cad80274f08aac287bdccfb38951c Mon Sep 17 00:00:00 2001
From: Paul <paulmakles@gmail.com>
Date: Mon, 21 Jun 2021 14:20:29 +0100
Subject: [PATCH] TextAreaAutoSize test

---
 src/components/ui/TextArea.tsx       |   6 +-
 src/lib/TextAreaAutoSize.tsx         | 105 +++++++++++++++++++++++++++
 src/pages/settings/panes/Profile.tsx |   8 +-
 3 files changed, 113 insertions(+), 6 deletions(-)
 create mode 100644 src/lib/TextAreaAutoSize.tsx

diff --git a/src/components/ui/TextArea.tsx b/src/components/ui/TextArea.tsx
index ed15695..cb4bc81 100644
--- a/src/components/ui/TextArea.tsx
+++ b/src/components/ui/TextArea.tsx
@@ -4,15 +4,17 @@
 // import { useState, useEffect, useRef, useLayoutEffect } from "preact/hooks";
 import styled, { css } from "styled-components";
 
-interface Props {
+export interface TextAreaProps {
     code?: boolean;
+    padding?: number;
 }
 
-export default styled.textarea<Props>`
+export default styled.textarea<TextAreaProps>`
     width: 100%;
     resize: none;
     display: block;
     border-radius: 4px;
+    padding: ${ props => props.padding ?? 16 }px;
 
     color: var(--foreground);
     border: 2px solid transparent;
diff --git a/src/lib/TextAreaAutoSize.tsx b/src/lib/TextAreaAutoSize.tsx
new file mode 100644
index 0000000..2b1fd73
--- /dev/null
+++ b/src/lib/TextAreaAutoSize.tsx
@@ -0,0 +1,105 @@
+import styled from "styled-components";
+import TextArea, { TextAreaProps } from "../components/ui/TextArea";
+import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
+
+type TextAreaAutoSizeProps = Omit<JSX.HTMLAttributes<HTMLTextAreaElement>, 'style' | 'value'> & TextAreaProps & {
+    autoFocus?: boolean,
+    minHeight?: number,
+    maxRows?: number,
+    value: string
+};
+
+const lineHeight = 20;
+
+const Ghost = styled.div`
+    width: 100%;
+    overflow: hidden;
+    position: relative;
+
+    > div {
+        width: 100%;
+        white-space: pre-wrap;
+        
+        top: 0;
+        position: absolute;
+        visibility: hidden;
+    }
+`;
+
+export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) {
+    const { autoFocus, minHeight, maxRows, value, padding, children, as, ...textAreaProps } = props;
+
+    const heightPadding = (padding ?? 0) * 2;
+    const minimumHeight = (minHeight ?? lineHeight) + heightPadding;
+
+    var height = Math.max(Math.min(value.split('\n').length, maxRows ?? Infinity) * lineHeight + heightPadding, minimumHeight);
+    const ref = useRef<HTMLTextAreaElement>();
+
+    /*function setHeight(h: number = lineHeight) {
+        let newHeight = Math.min(
+            Math.max(
+                lineHeight,
+                maxRows ? Math.min(h, maxRows * lineHeight) : h
+            ),
+            minHeight ?? Infinity
+        );
+
+        if (heightPadding) newHeight += heightPadding;
+        if (height !== newHeight) {
+            setHeightState(newHeight);
+        }
+    }*/
+
+    {/*useLayoutEffect(() => {
+        setHeight(ghost.current.clientHeight);
+    }, [ghost, value]);*/}
+
+    useEffect(() => {
+        autoFocus && ref.current.focus();
+    }, [value]);
+    
+    const inputSelected = () =>
+        ["TEXTAREA", "INPUT"].includes(document.activeElement?.nodeName ?? "");
+
+    useEffect(() => {
+        /* if (props.forceFocus) { // figure out what needed force focus
+            ref.current.focus();
+        } */
+
+        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]);
+
+    return <>
+        <TextArea
+            ref={ref}
+            value={value}
+            padding={padding}
+            style={{ height }}
+            {...textAreaProps} />
+        {/*<Ghost><div ref={ghost}>
+            { props.value.split('\n')
+                .map(x => `\u0020${x}`)
+                .join('\n') }
+        </div></Ghost>*/}
+    </>;
+}
diff --git a/src/pages/settings/panes/Profile.tsx b/src/pages/settings/panes/Profile.tsx
index aab0ae0..148f1b4 100644
--- a/src/pages/settings/panes/Profile.tsx
+++ b/src/pages/settings/panes/Profile.tsx
@@ -1,8 +1,8 @@
 import styles from "./Panes.module.scss";
 import Button from "../../../components/ui/Button";
 import { Users } from "revolt.js/dist/api/objects";
-import TextArea from "../../../components/ui/TextArea";
 import { IntlContext, Text, translate } from "preact-i18n";
+import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
 import { useContext, useEffect, useState } from "preact/hooks";
 import { FileUploader } from "../../../context/revoltjs/FileUploads";
 import { useForceUpdate, useSelf } from "../../../context/revoltjs/hooks";
@@ -93,9 +93,9 @@ export function Profile() {
             <h3>
                 <Text id="app.settings.pages.profile.info" />
             </h3>
-            <TextArea
-                // maxRows={10}
-                // minHeight={200}
+            <TextAreaAutoSize
+                maxRows={10}
+                minHeight={200}
                 maxLength={2000}
                 value={profile?.content ?? ""}
                 disabled={typeof profile === "undefined"}
-- 
GitLab