diff --git a/external/lang b/external/lang index 210172de..a84270a2 160000 --- a/external/lang +++ b/external/lang @@ -1 +1 @@ -Subproject commit 210172de724fcd5adeacec221bd9da30350afc06 +Subproject commit a84270a2b941a51f4785e543c0882ce9f7f004a6 diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx index 800c1df0..87dfeedd 100644 --- a/src/components/common/messaging/Message.tsx +++ b/src/components/common/messaging/Message.tsx @@ -6,18 +6,21 @@ import { Children } from "../../../types/Preact"; import Attachment from "./attachments/Attachment"; import { attachContextMenu } from "preact-context-menu"; import { useUser } from "../../../context/revoltjs/hooks"; +import { QueuedMessage } from "../../../redux/reducers/queue"; import { MessageObject } from "../../../context/revoltjs/util"; import MessageBase, { MessageContent, MessageDetail, MessageInfo } from "./MessageBase"; +import Overline from "../../ui/Overline"; interface Props { attachContext?: boolean + queued?: QueuedMessage message: MessageObject contrast?: boolean content?: Children head?: boolean } -export default function Message({ attachContext, message, contrast, content: replacement, head }: Props) { +export default function Message({ attachContext, message, contrast, content: replacement, head, queued }: Props) { // TODO: Can improve re-renders here by providing a list // TODO: of dependencies. We only need to update on u/avatar. let user = useUser(message.author); @@ -25,9 +28,11 @@ export default function Message({ attachContext, message, contrast, content: rep const content = message.content as string; return ( + contrast={contrast} + sending={typeof queued !== 'undefined'} + failed={typeof queued?.error !== 'undefined'} + onContextMenu={attachContext ? attachContextMenu('Menu', { message, contextualChannel: message.channel, queued }) : undefined}> { head ? : @@ -39,6 +44,7 @@ export default function Message({ attachContext, message, contrast, content: rep } { replacement ?? } + { queued?.error && } { message.attachments?.map((attachment, index) => 0 || content.length > 0 } />) } { message.embeds?.map((embed, index) => diff --git a/src/components/common/messaging/MessageBase.tsx b/src/components/common/messaging/MessageBase.tsx index 7284dba4..20473381 100644 --- a/src/components/common/messaging/MessageBase.tsx +++ b/src/components/common/messaging/MessageBase.tsx @@ -7,7 +7,7 @@ import { MessageObject } from "../../../context/revoltjs/util"; export interface BaseMessageProps { head?: boolean, - status?: boolean, + failed?: boolean, mention?: boolean, blocked?: boolean, sending?: boolean, @@ -49,7 +49,7 @@ export default styled.div` color: var(--tertiary-foreground); ` } - ${ props => props.status && css` + ${ props => props.failed && css` color: var(--error); ` } diff --git a/src/components/common/messaging/MessageBox.tsx b/src/components/common/messaging/MessageBox.tsx index f0e6a8a1..ed0f78e4 100644 --- a/src/components/common/messaging/MessageBox.tsx +++ b/src/components/common/messaging/MessageBox.tsx @@ -19,6 +19,7 @@ import { SingletonMessageRenderer, SMOOTH_SCROLL_ON_RECEIVE } from "../../../lib import FilePreview from './bars/FilePreview'; import { debounce } from "../../../lib/debounce"; +import { internalEmit } from "../../../lib/eventEmitter"; type Props = WithDispatcher & { channel: Channel; @@ -237,11 +238,22 @@ function MessageBox({ channel, draft, dispatcher }: Props) { /> { + if ( + e.key === "ArrowUp" && + (!draft || draft.length === 0) + ) { + e.preventDefault(); + internalEmit("MessageRenderer", "edit_last"); + return; + } + if (!e.shiftKey && e.key === "Enter" && !isTouchscreenDevice) { e.preventDefault(); return send(); diff --git a/src/components/ui/TextArea.tsx b/src/components/ui/TextArea.tsx index 7cdde086..f91b4286 100644 --- a/src/components/ui/TextArea.tsx +++ b/src/components/ui/TextArea.tsx @@ -48,142 +48,3 @@ export default styled.textarea` font-family: 'Open Sans', sans-serif; ` } `; - -/*export interface TextAreaProps { - id?: string; - value: string; - maxRows?: number; - padding?: number; - minHeight?: number; - disabled?: boolean; - maxLength?: number; - className?: string; - autoFocus?: boolean; - forceFocus?: boolean; - placeholder?: string; - onKeyDown?: (ev: KeyboardEvent) => void; - onKeyUp?: (ev: KeyboardEvent) => void; - onChange: ( - value: string, - ev: JSX.TargetedEvent - ) => void; - onFocus?: (current: HTMLTextAreaElement) => void; - onBlur?: () => void; -} - -const lineHeight = 20; - -export const TextAreaB = memo((props: TextAreaProps) => { - const padding = props.padding ? props.padding * 2 : 0; - - const [height, setHeightState] = useState( - props.minHeight ?? lineHeight + padding - ); - const ghost = useRef(); - const ref = useRef(); - - function setHeight(h: number = lineHeight) { - let newHeight = Math.min( - Math.max( - lineHeight, - props.maxRows ? Math.min(h, props.maxRows * lineHeight) : h - ), - props.minHeight ?? Infinity - ); - - if (props.padding) newHeight += padding; - if (height !== newHeight) { - setHeightState(newHeight); - } - } - - function onChange(ev: JSX.TargetedEvent) { - props.onChange(ev.currentTarget.value, ev); - } - - useLayoutEffect(() => { - setHeight(ghost.current.clientHeight); - }, [ghost, props.value]); - - useEffect(() => { - if (props.autoFocus) ref.current.focus(); - }, [props.value]); - - const inputSelected = () => - ["TEXTAREA", "INPUT"].includes(document.activeElement?.nodeName ?? ""); - - useEffect(() => { - if (props.forceFocus) { - ref.current.focus(); - } - - if (props.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 = props.value; - - if (!props.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]); - - useEffect(() => { - function focus(textarea_id: string) { - if (props.id === textarea_id) { - ref.current.focus(); - } - } - - // InternalEventEmitter.addListener("focus_textarea", focus); - // return () => - // InternalEventEmitter.removeListener("focus_textarea", focus); - }, [ref]); - - return ( -
-