feat(threads): up-arrow edits your last thread reply (+ fix cross-fire)
The thread composer reused RoomInput's hardcoded editableName="RoomInput", so the main timeline's global up-arrow "edit last message" handler fired while focused in a thread composer and targeted the MAIN timeline's last message (wrong), and there was no up-arrow edit for the thread itself. - Make editableName a RoomInput prop (default "RoomInput"); the thread composer passes "ThreadInput", so the two up-arrow handlers never cross-fire. - Add an up-arrow-edit handler to ThreadTimeline (parity with RoomTimeline): empty thread composer + Up -> edit the latest editable reply in that thread, using thread.liveTimeline + canEditEvent + setEditId. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -196,6 +196,7 @@ export function ThreadPanel({ room, threadId, requestClose }: ThreadPanelProps)
|
||||
roomId={room.roomId}
|
||||
threadRootId={threadId}
|
||||
editor={editor}
|
||||
editableName="ThreadInput"
|
||||
fileDropContainerRef={fileDropContainerRef}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -32,11 +32,12 @@ import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { Badge, Box, Chip, Icon, Icons, Line, Scroll, Spinner, Text, color, config } from 'folds';
|
||||
import classNames from 'classnames';
|
||||
import { Opts as LinkifyOpts } from 'linkifyjs';
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { eventWithShortcode, factoryEventSentBy } from '../../../utils/matrix';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { useVirtualPaginator, ItemRange } from '../../../hooks/useVirtualPaginator';
|
||||
import { useAlive } from '../../../hooks/useAlive';
|
||||
import { scrollToBottom } from '../../../utils/dom';
|
||||
import { editableActiveElement, scrollToBottom } from '../../../utils/dom';
|
||||
import {
|
||||
DefaultPlaceholder,
|
||||
MessageBase,
|
||||
@@ -55,9 +56,11 @@ import {
|
||||
renderMatrixMention,
|
||||
} from '../../../plugins/react-custom-html-parser';
|
||||
import {
|
||||
canEditEvent,
|
||||
decryptAllTimelineEvent,
|
||||
getEditedEvent,
|
||||
getEventReactions,
|
||||
getLatestEditableEvt,
|
||||
getMemberName,
|
||||
getReactionContent,
|
||||
reactionOrEditEvent,
|
||||
@@ -76,7 +79,8 @@ import {
|
||||
today,
|
||||
yesterday,
|
||||
} from '../../../utils/time';
|
||||
import { createMentionElement, moveCursor } from '../../../components/editor';
|
||||
import { createMentionElement, isEmptyEditor, moveCursor } from '../../../components/editor';
|
||||
import { useKeyDown } from '../../../hooks/useKeyDown';
|
||||
import { roomIdToReplyDraftAtomFamily } from '../../../state/room/roomInputDrafts';
|
||||
import { usePowerLevelsContext } from '../../../hooks/usePowerLevels';
|
||||
import { GetContentCallback, MessageEvent, StateEvent } from '../../../../types/matrix/room';
|
||||
@@ -580,6 +584,32 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) {
|
||||
[editor],
|
||||
);
|
||||
|
||||
// Up-arrow in the (empty) thread composer edits your last editable reply in
|
||||
// this thread — parity with the main timeline. Gated on the thread composer's
|
||||
// distinct editableName so it and the main handler never cross-fire.
|
||||
useKeyDown(
|
||||
window,
|
||||
useCallback(
|
||||
(evt) => {
|
||||
if (
|
||||
isKeyHotkey('arrowup', evt) &&
|
||||
editableActiveElement() &&
|
||||
document.activeElement?.getAttribute('data-editable-name') === 'ThreadInput' &&
|
||||
isEmptyEditor(editor)
|
||||
) {
|
||||
const editableEvt = getLatestEditableEvt(thread.liveTimeline, (mEvt) =>
|
||||
canEditEvent(mx, mEvt),
|
||||
);
|
||||
const editableEvtId = editableEvt?.getId();
|
||||
if (!editableEvtId) return;
|
||||
setEditId(editableEvtId);
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
[mx, thread, editor],
|
||||
),
|
||||
);
|
||||
|
||||
const handleOpenReply: MouseEventHandler = useCallback(
|
||||
(evt) => {
|
||||
const targetId = evt.currentTarget.getAttribute('data-event-id');
|
||||
|
||||
Reference in New Issue
Block a user