mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-22 15:10:57 -05:00
TextAreaAutoSize test
This commit is contained in:
parent
3c6e3b9fbf
commit
d965b20ee2
3 changed files with 113 additions and 6 deletions
|
@ -4,15 +4,17 @@
|
||||||
// import { useState, useEffect, useRef, useLayoutEffect } from "preact/hooks";
|
// import { useState, useEffect, useRef, useLayoutEffect } from "preact/hooks";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
|
||||||
interface Props {
|
export interface TextAreaProps {
|
||||||
code?: boolean;
|
code?: boolean;
|
||||||
|
padding?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default styled.textarea<Props>`
|
export default styled.textarea<TextAreaProps>`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
resize: none;
|
resize: none;
|
||||||
display: block;
|
display: block;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
padding: ${ props => props.padding ?? 16 }px;
|
||||||
|
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
|
|
105
src/lib/TextAreaAutoSize.tsx
Normal file
105
src/lib/TextAreaAutoSize.tsx
Normal 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>*/}
|
||||||
|
</>;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
import Button from "../../../components/ui/Button";
|
import Button from "../../../components/ui/Button";
|
||||||
import { Users } from "revolt.js/dist/api/objects";
|
import { Users } from "revolt.js/dist/api/objects";
|
||||||
import TextArea from "../../../components/ui/TextArea";
|
|
||||||
import { IntlContext, Text, translate } from "preact-i18n";
|
import { IntlContext, Text, translate } from "preact-i18n";
|
||||||
|
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
|
||||||
import { useContext, useEffect, useState } from "preact/hooks";
|
import { useContext, useEffect, useState } from "preact/hooks";
|
||||||
import { FileUploader } from "../../../context/revoltjs/FileUploads";
|
import { FileUploader } from "../../../context/revoltjs/FileUploads";
|
||||||
import { useForceUpdate, useSelf } from "../../../context/revoltjs/hooks";
|
import { useForceUpdate, useSelf } from "../../../context/revoltjs/hooks";
|
||||||
|
@ -93,9 +93,9 @@ export function Profile() {
|
||||||
<h3>
|
<h3>
|
||||||
<Text id="app.settings.pages.profile.info" />
|
<Text id="app.settings.pages.profile.info" />
|
||||||
</h3>
|
</h3>
|
||||||
<TextArea
|
<TextAreaAutoSize
|
||||||
// maxRows={10}
|
maxRows={10}
|
||||||
// minHeight={200}
|
minHeight={200}
|
||||||
maxLength={2000}
|
maxLength={2000}
|
||||||
value={profile?.content ?? ""}
|
value={profile?.content ?? ""}
|
||||||
disabled={typeof profile === "undefined"}
|
disabled={typeof profile === "undefined"}
|
||||||
|
|
Loading…
Reference in a new issue