diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -57,6 +57,7 @@ threadActualMembers, checkIfDefaultMembersAreVoiced, draftKeyFromThreadID, + useThreadChatMentionCandidates, } from 'lib/shared/thread-utils.js'; import type { CalendarQuery } from 'lib/types/entry-types.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; @@ -1258,13 +1259,17 @@ parentThreadInfo, ); + const chatMentionCandidates = useThreadChatMentionCandidates( + props.threadInfo, + ); + const messageEditingContext = React.useContext(MessageEditingContext); const editedMessageInfo = messageEditingContext?.editState.editedMessage; const editedMessagePreview = useMessagePreview( editedMessageInfo, props.threadInfo, - getDefaultTextMessageRules().simpleMarkdownRules, + getDefaultTextMessageRules(chatMentionCandidates).simpleMarkdownRules, ); const editMessage = useEditMessage(); diff --git a/native/chat/message-list-types.js b/native/chat/message-list-types.js --- a/native/chat/message-list-types.js +++ b/native/chat/message-list-types.js @@ -4,6 +4,7 @@ import invariant from 'invariant'; import * as React from 'react'; +import { useThreadChatMentionCandidates } from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { type UserInfo } from 'lib/types/user-types.js'; @@ -35,7 +36,11 @@ React.createContext(); function useMessageListContext(threadInfo: ThreadInfo) { - const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo); + const chatMentionCandidates = useThreadChatMentionCandidates(threadInfo); + const getTextMessageMarkdownRules = useTextMessageRulesFunc( + threadInfo, + chatMentionCandidates, + ); return React.useMemo( () => ({ getTextMessageMarkdownRules, diff --git a/native/chat/message-preview.react.js b/native/chat/message-preview.react.js --- a/native/chat/message-preview.react.js +++ b/native/chat/message-preview.react.js @@ -5,6 +5,7 @@ import { Text } from 'react-native'; import { useMessagePreview } from 'lib/shared/message-utils.js'; +import { useThreadChatMentionCandidates } from 'lib/shared/thread-utils.js'; import { type MessageInfo } from 'lib/types/message-types.js'; import { type ThreadInfo } from 'lib/types/thread-types.js'; @@ -18,10 +19,12 @@ }; function MessagePreview(props: Props): React.Node { const { messageInfo, threadInfo } = props; + + const chatMentionCandidates = useThreadChatMentionCandidates(threadInfo); const messagePreviewResult = useMessagePreview( messageInfo, threadInfo, - getDefaultTextMessageRules().simpleMarkdownRules, + getDefaultTextMessageRules(chatMentionCandidates).simpleMarkdownRules, ); invariant( messagePreviewResult, diff --git a/native/chat/sidebar-input-bar-height-measurer.react.js b/native/chat/sidebar-input-bar-height-measurer.react.js --- a/native/chat/sidebar-input-bar-height-measurer.react.js +++ b/native/chat/sidebar-input-bar-height-measurer.react.js @@ -4,6 +4,7 @@ import { View, StyleSheet } from 'react-native'; import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js'; +import { useThreadChatMentionCandidates } from 'lib/shared/thread-utils.js'; import { DummyChatInputBar } from './chat-input-bar.react.js'; import { useMessageListScreenWidth } from './composed-message-width.js'; @@ -21,9 +22,17 @@ const width = useMessageListScreenWidth(); const loggedInUserInfo = useLoggedInUserInfo(); + const chatMentionCandidates = useThreadChatMentionCandidates( + sourceMessage.threadInfo, + ); const sidebarThreadInfo = React.useMemo( - () => getUnresolvedSidebarThreadInfo({ sourceMessage, loggedInUserInfo }), - [sourceMessage, loggedInUserInfo], + () => + getUnresolvedSidebarThreadInfo({ + sourceMessage, + loggedInUserInfo, + chatMentionCandidates, + }), + [sourceMessage, loggedInUserInfo, chatMentionCandidates], ); if (!sidebarThreadInfo) { return null; diff --git a/native/chat/sidebar-navigation.js b/native/chat/sidebar-navigation.js --- a/native/chat/sidebar-navigation.js +++ b/native/chat/sidebar-navigation.js @@ -8,8 +8,12 @@ import { createPendingSidebar, createUnresolvedPendingSidebar, + useThreadChatMentionCandidates, } from 'lib/shared/thread-utils.js'; -import type { ThreadInfo } from 'lib/types/thread-types.js'; +import type { + ThreadInfo, + ChatMentionCandidates, +} from 'lib/types/thread-types.js'; import type { LoggedInUserInfo } from 'lib/types/user-types.js'; import type { GetENSNames } from 'lib/utils/ens-helpers.js'; @@ -21,11 +25,12 @@ type GetUnresolvedSidebarThreadInfoInput = { +sourceMessage: ChatMessageInfoItemWithHeight, +loggedInUserInfo: ?LoggedInUserInfo, + +chatMentionCandidates: ChatMentionCandidates, }; function getUnresolvedSidebarThreadInfo( input: GetUnresolvedSidebarThreadInfoInput, ): ?ThreadInfo { - const { sourceMessage, loggedInUserInfo } = input; + const { sourceMessage, loggedInUserInfo, chatMentionCandidates } = input; const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; if (threadCreatedFromMessage) { return threadCreatedFromMessage; @@ -40,7 +45,8 @@ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, loggedInUserInfo, - markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + markdownRules: getDefaultTextMessageRules(chatMentionCandidates) + .simpleMarkdownRules, }); } @@ -51,7 +57,12 @@ async function getSidebarThreadInfo( input: GetSidebarThreadInfoInput, ): Promise { - const { sourceMessage, loggedInUserInfo, getENSNames } = input; + const { + sourceMessage, + loggedInUserInfo, + getENSNames, + chatMentionCandidates, + } = input; const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; if (threadCreatedFromMessage) { return threadCreatedFromMessage; @@ -66,7 +77,8 @@ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, loggedInUserInfo, - markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + markdownRules: getDefaultTextMessageRules(chatMentionCandidates) + .simpleMarkdownRules, getENSNames, }); } @@ -77,16 +89,24 @@ const loggedInUserInfo = useLoggedInUserInfo(); const navigateToThread = useNavigateToThread(); const cacheContext = React.useContext(ENSCacheContext); + const chatMentionCandidates = useThreadChatMentionCandidates(item.threadInfo); const { getENSNames } = cacheContext; return React.useCallback(async () => { const threadInfo = await getSidebarThreadInfo({ sourceMessage: item, loggedInUserInfo, getENSNames, + chatMentionCandidates, }); invariant(threadInfo, 'threadInfo should be set'); navigateToThread({ threadInfo }); - }, [navigateToThread, item, loggedInUserInfo, getENSNames]); + }, [ + item, + loggedInUserInfo, + getENSNames, + chatMentionCandidates, + navigateToThread, + ]); } function useAnimatedNavigateToSidebar( diff --git a/native/chat/utils.js b/native/chat/utils.js --- a/native/chat/utils.js +++ b/native/chat/utils.js @@ -7,7 +7,10 @@ import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js'; import { colorIsDark } from 'lib/shared/color-utils.js'; import { messageKey } from 'lib/shared/message-utils.js'; -import { viewerIsMember } from 'lib/shared/thread-utils.js'; +import { + viewerIsMember, + useThreadChatMentionCandidates, +} from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { clusterEndHeight } from './chat-constants.js'; @@ -206,9 +209,17 @@ } = chatContext; const loggedInUserInfo = useLoggedInUserInfo(); + const chatMentionCandidates = useThreadChatMentionCandidates( + sourceMessage.threadInfo, + ); const sidebarThreadInfo = React.useMemo( - () => getUnresolvedSidebarThreadInfo({ sourceMessage, loggedInUserInfo }), - [sourceMessage, loggedInUserInfo], + () => + getUnresolvedSidebarThreadInfo({ + sourceMessage, + loggedInUserInfo, + chatMentionCandidates, + }), + [sourceMessage, loggedInUserInfo, chatMentionCandidates], ); const currentInputBarHeight = diff --git a/native/markdown/rules.react.js b/native/markdown/rules.react.js --- a/native/markdown/rules.react.js +++ b/native/markdown/rules.react.js @@ -6,7 +6,11 @@ import * as SimpleMarkdown from 'simple-markdown'; import * as SharedMarkdown from 'lib/shared/markdown.js'; -import type { RelativeMemberInfo, ThreadInfo } from 'lib/types/thread-types.js'; +import type { + RelativeMemberInfo, + ThreadInfo, + ChatMentionCandidates, +} from 'lib/types/thread-types.js'; import MarkdownLink from './markdown-link.react.js'; import MarkdownParagraph from './markdown-paragraph.react.js'; @@ -353,19 +357,21 @@ function useTextMessageRulesFunc( threadInfo: ThreadInfo, + chatMentionCandidates: ChatMentionCandidates, ): (useDarkStyle: boolean) => MarkdownRules { const { members } = threadInfo; return React.useMemo( () => _memoize<[boolean], MarkdownRules>((useDarkStyle: boolean) => - textMessageRules(members, useDarkStyle), + textMessageRules(members, chatMentionCandidates, useDarkStyle), ), - [members], + [members, chatMentionCandidates], ); } function textMessageRules( members: $ReadOnlyArray, + chatMentionCandidates: ChatMentionCandidates, useDarkStyle: boolean, ): MarkdownRules { const styles = getMarkdownStyles(useDarkStyle ? 'dark' : 'light'); @@ -397,9 +403,14 @@ let defaultTextMessageRules = null; -function getDefaultTextMessageRules(): MarkdownRules { +function getDefaultTextMessageRules( + overrideDefaultChatMentionCandidates: ChatMentionCandidates = {}, +): MarkdownRules { + if (Object.keys(overrideDefaultChatMentionCandidates).length > 0) { + return textMessageRules([], overrideDefaultChatMentionCandidates, false); + } if (!defaultTextMessageRules) { - defaultTextMessageRules = textMessageRules([], false); + defaultTextMessageRules = textMessageRules([], {}, false); } return defaultTextMessageRules; }