TextAreaAutoSize test

This commit is contained in:
Paul 2021-06-21 14:20:29 +01:00
parent 3c6e3b9fbf
commit d965b20ee2
3 changed files with 113 additions and 6 deletions

View file

@ -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;

View file

@ -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>*/}
</>;
}

View file

@ -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"}