From 86d9bfff8d95400ec5307a7361a45a0cc201eba7 Mon Sep 17 00:00:00 2001 From: Arjun Mahanti Date: Wed, 26 Aug 2026 13:56:42 -0400 Subject: [PATCH] refactor(desktop): satisfy prototype quality gates Co-authored-by: Codex Signed-off-by: Arjun Mahanti --- .../messages/ui/BestieChatPopover.tsx | 2 +- .../messages/ui/BestieMessagePopover.tsx | 6 +- .../features/messages/ui/MessageActionBar.tsx | 83 ++----------------- .../ui/MessageActionToolbarHelpers.tsx | 74 +++++++++++++++++ .../features/messages/ui/MessageComposer.tsx | 7 +- .../src/features/messages/ui/MessageRow.tsx | 5 +- .../sidebar/ui/AppSidebarPinnedHeader.tsx | 2 +- 7 files changed, 89 insertions(+), 90 deletions(-) create mode 100644 desktop/src/features/messages/ui/MessageActionToolbarHelpers.tsx diff --git a/desktop/src/features/messages/ui/BestieChatPopover.tsx b/desktop/src/features/messages/ui/BestieChatPopover.tsx index 2a15b0a3e8..6a8b9bd507 100644 --- a/desktop/src/features/messages/ui/BestieChatPopover.tsx +++ b/desktop/src/features/messages/ui/BestieChatPopover.tsx @@ -207,7 +207,7 @@ export function BestieChatPopover() { >
-

+

{message.author}

-

+

{message.time}

@@ -122,7 +122,7 @@ export function BestieMessagePanel({ data-testid={`bestie-message-snapshot-body-${message.id}`} > void; -}) { - const displayName = emojiDisplayName(emoji); - const mediaUrl = customEmojiUrl ? rewriteRelayUrl(customEmojiUrl) : null; - - return ( - - - - - {displayName} - - ); -} - -function isCustomEmojiShortcode(emoji: string) { - return emoji.startsWith(":") && emoji.endsWith(":"); -} - export const MessageActionBar = React.memo(function MessageActionBar({ channelId, message, @@ -834,7 +765,7 @@ export const MessageActionBar = React.memo(function MessageActionBar({ > void; +}) { + const displayName = emojiDisplayName(emoji); + const mediaUrl = customEmojiUrl ? rewriteRelayUrl(customEmojiUrl) : null; + + return ( + + + + + {displayName} + + ); +} + +export function isCustomEmojiShortcode(emoji: string) { + return emoji.startsWith(":") && emoji.endsWith(":"); +} diff --git a/desktop/src/features/messages/ui/MessageComposer.tsx b/desktop/src/features/messages/ui/MessageComposer.tsx index 70fb3a2792..870898e926 100644 --- a/desktop/src/features/messages/ui/MessageComposer.tsx +++ b/desktop/src/features/messages/ui/MessageComposer.tsx @@ -419,16 +419,13 @@ function MessageComposerImpl({ setSpoileredAttachmentUrls(restoredSpoileredAttachmentUrls); } }, [editTarget?.id]); - // ── Focus on reply ────────────────────────────────────────────────── - // Use focusPreserve so that re-renders (e.g. new messages arriving in - // a thread) don't yank the cursor to the end while the user is editing. + // Preserve the cursor when reply-driven rerenders refocus the composer. React.useEffect(() => { if (!replyTarget || composerDisabled) return; richText.focusPreserve(); }, [composerDisabled, replyTarget, richText.focusPreserve]); useComposerAutofocus(richText.focus, effectiveDraftKey, composerDisabled); - // Hooks return a plain-text edit descriptor; `replacePlainTextRange` - // applies it as a single ProseMirror transaction (no markdown round-trip). + // Apply autocomplete as one ProseMirror transaction, without a markdown round-trip. const applyAutocompleteEdit = React.useCallback( (edit: AutocompleteEdit) => { richText.replacePlainTextRange( diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx index 7ad5b1fd0c..637444f030 100644 --- a/desktop/src/features/messages/ui/MessageRow.tsx +++ b/desktop/src/features/messages/ui/MessageRow.tsx @@ -933,9 +933,8 @@ export const MessageRow = React.memo(
); - // Callbacks (onReply, onToggleReaction) intentionally excluded: inline arrows - // from parent create new refs every render — including them defeats memo. }, + // Ignore unstable callback identities; compare createdAt for timestamp-derived UI. (prev, next) => prev.message.id === next.message.id && prev.message.pubkey === next.message.pubkey && @@ -946,8 +945,6 @@ export const MessageRow = React.memo( prev.message.ownerLabel === next.message.ownerLabel && prev.message.avatarUrl === next.message.avatarUrl && prev.message.accent === next.message.accent && - // The header timestamp and hover gutter both derive from createdAt (the - // old `time` prop was the same value pre-formatted; this row reads neither). prev.message.createdAt === next.message.createdAt && prev.message.depth === next.message.depth && prev.message.kind === next.message.kind && diff --git a/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx b/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx index 53db27efc7..cd5f42f5be 100644 --- a/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx +++ b/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx @@ -182,7 +182,7 @@ export function AppSidebarPrimaryMenu({ >