diff --git a/src/components/common/messaging/MessageBase.tsx b/src/components/common/messaging/MessageBase.tsx index afddb0d5..1ed75ffd 100644 --- a/src/components/common/messaging/MessageBase.tsx +++ b/src/components/common/messaging/MessageBase.tsx @@ -151,7 +151,7 @@ export const MessageContent = styled.div` flex-grow: 1; display: flex; // overflow: hidden; - font-size: 0.875rem; + font-size: var(--text-size); flex-direction: column; justify-content: center; `; diff --git a/src/components/common/messaging/MessageBox.tsx b/src/components/common/messaging/MessageBox.tsx index 340d073b..1243cbb3 100644 --- a/src/components/common/messaging/MessageBox.tsx +++ b/src/components/common/messaging/MessageBox.tsx @@ -65,7 +65,7 @@ const Base = styled.div` background: var(--message-box); textarea { - font-size: 0.875rem; + font-size: var(--text-size); background: transparent; } `; @@ -75,7 +75,7 @@ const Blocked = styled.div` align-items: center; padding: 14px 0; user-select: none; - font-size: 0.875rem; + font-size: var(--text-size); color: var(--tertiary-foreground); svg { @@ -423,10 +423,10 @@ function MessageBox({ channel, draft }: Props) { autoFocus hideBorder maxRows={20} - padding={12} id="message" - value={draft ?? ""} onKeyUp={onKeyUp} + value={draft ?? ""} + padding="var(--message-box-padding)" onKeyDown={(e) => { if (onKeyDown(e)) return; diff --git a/src/components/ui/ComboBox.tsx b/src/components/ui/ComboBox.tsx index 5d5c7963..5b794b49 100644 --- a/src/components/ui/ComboBox.tsx +++ b/src/components/ui/ComboBox.tsx @@ -6,7 +6,7 @@ export default styled.select` font-family: inherit; color: var(--secondary-foreground); background: var(--secondary-background); - font-size: 0.875rem; + font-size: var(--text-size); border: none; outline: 2px solid transparent; transition: outline-color 0.2s ease-in-out; diff --git a/src/components/ui/TextArea.tsx b/src/components/ui/TextArea.tsx index ab087d57..1a2016bc 100644 --- a/src/components/ui/TextArea.tsx +++ b/src/components/ui/TextArea.tsx @@ -2,8 +2,8 @@ import styled, { css } from "styled-components"; export interface TextAreaProps { code?: boolean; - padding?: number; - lineHeight?: number; + padding?: string; + lineHeight?: string; hideBorder?: boolean; } @@ -17,8 +17,8 @@ export default styled.textarea` display: block; color: var(--foreground); background: var(--secondary-background); - padding: ${(props) => props.padding ?? DEFAULT_TEXT_AREA_PADDING}px; - line-height: ${(props) => props.lineHeight ?? DEFAULT_LINE_HEIGHT}px; + padding: ${(props) => (props.padding) ?? 'var(--textarea-padding)'}; + line-height: ${(props) => (props.lineHeight) ?? 'var(--textarea-line-height)'}; ${(props) => props.hideBorder && @@ -31,7 +31,7 @@ export default styled.textarea` css` border-radius: 4px; transition: border-color 0.2s ease-in-out; - border: ${TEXT_AREA_BORDER_WIDTH}px solid transparent; + border: var(--input-border-width) solid transparent; `} &:focus { @@ -40,7 +40,7 @@ export default styled.textarea` ${(props) => !props.hideBorder && css` - border: ${TEXT_AREA_BORDER_WIDTH}px solid var(--accent); + border: var(--input-border-width) solid var(--accent); `} } diff --git a/src/lib/TextAreaAutoSize.tsx b/src/lib/TextAreaAutoSize.tsx index b067b95e..5660dedf 100644 --- a/src/lib/TextAreaAutoSize.tsx +++ b/src/lib/TextAreaAutoSize.tsx @@ -1,4 +1,6 @@ -import { useEffect, useRef } from "preact/hooks"; +import styled from "styled-components"; + +import { useEffect, useLayoutEffect, useRef } from "preact/hooks"; import TextArea, { DEFAULT_LINE_HEIGHT, @@ -12,7 +14,7 @@ import { isTouchscreenDevice } from "./isTouchscreenDevice"; type TextAreaAutoSizeProps = Omit< JSX.HTMLAttributes, - "style" | "value" + "style" | "value" | "onChange" > & TextAreaProps & { forceFocus?: boolean; @@ -22,8 +24,37 @@ type TextAreaAutoSizeProps = Omit< value: string; id?: string; + + onChange?: (ev: JSX.TargetedEvent) => void; }; +const Container = styled.div` + flex-grow: 1; + display: flex; + flex-direction: column; +`; + +const Ghost = styled.div<{ lineHeight: string, maxRows: number }>` + flex: 0; + width: 100%; + overflow: hidden; + visibility: hidden; + position: relative; + + > div { + width: 100%; + white-space: pre-wrap; + word-break: break-all; + + top: 0; + position: absolute; + font-size: var(--text-size); + line-height: ${(props) => props.lineHeight}; + + max-height: calc(calc( ${(props) => props.lineHeight} * ${ (props) => props.maxRows } )); + } +`; + export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { const { autoFocus, @@ -39,19 +70,13 @@ export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { onChange, ...textAreaProps } = props; - const line = lineHeight ?? DEFAULT_LINE_HEIGHT; - - const heightPadding = - ((padding ?? DEFAULT_TEXT_AREA_PADDING) + - (hideBorder ? 0 : TEXT_AREA_BORDER_WIDTH)) * - 2; - const height = Math.max( - Math.min(value.split("\n").length, maxRows ?? Infinity) * line + - heightPadding, - minHeight ?? 0, - ); const ref = useRef(); + const ghost = useRef(); + + useLayoutEffect(() => { + ref.current.style.height = ghost.current.clientHeight + 'px'; + }, [ghost, props.value]); useEffect(() => { if (isTouchscreenDevice) return; @@ -101,18 +126,29 @@ export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { }, [ref]); return ( -