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 { useChatMentionCandidatesObj } from 'lib/shared/thread-utils.js'; import { DummyChatInputBar } from './chat-input-bar.react.js'; import { useMessageListScreenWidth } from './composed-message-width.js'; @@ -21,9 +22,15 @@ const width = useMessageListScreenWidth(); const loggedInUserInfo = useLoggedInUserInfo(); + const chatMentionCandidatesObj = useChatMentionCandidatesObj(); const sidebarThreadInfo = React.useMemo( - () => getUnresolvedSidebarThreadInfo({ sourceMessage, loggedInUserInfo }), - [sourceMessage, loggedInUserInfo], + () => + getUnresolvedSidebarThreadInfo({ + sourceMessage, + loggedInUserInfo, + chatMentionCandidatesObj, + }), + [sourceMessage, loggedInUserInfo, chatMentionCandidatesObj], ); 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,13 @@ import { createPendingSidebar, createUnresolvedPendingSidebar, + useChatMentionCandidatesObj, + threadChatMentionCandidates, } from 'lib/shared/thread-utils.js'; -import type { ThreadInfo } from 'lib/types/thread-types.js'; +import type { + ThreadInfo, + ChatMentionCandidatesObj, +} 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 +26,12 @@ type GetUnresolvedSidebarThreadInfoInput = { +sourceMessage: ChatMessageInfoItemWithHeight, +loggedInUserInfo: ?LoggedInUserInfo, + +chatMentionCandidatesObj: ChatMentionCandidatesObj, }; function getUnresolvedSidebarThreadInfo( input: GetUnresolvedSidebarThreadInfoInput, ): ?ThreadInfo { - const { sourceMessage, loggedInUserInfo } = input; + const { sourceMessage, loggedInUserInfo, chatMentionCandidatesObj } = input; const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; if (threadCreatedFromMessage) { return threadCreatedFromMessage; @@ -36,22 +42,35 @@ } const { messageInfo, threadInfo } = sourceMessage; + const chatMentionCandidates = threadChatMentionCandidates( + threadInfo, + chatMentionCandidatesObj, + ); + return createUnresolvedPendingSidebar({ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, loggedInUserInfo, - markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + markdownRules: getDefaultTextMessageRules(chatMentionCandidates) + .simpleMarkdownRules, }); } type GetSidebarThreadInfoInput = { - ...GetUnresolvedSidebarThreadInfoInput, + +sourceMessage: ChatMessageInfoItemWithHeight, + +loggedInUserInfo: ?LoggedInUserInfo, +getENSNames: ?GetENSNames, + +chatMentionCandidatesObj: ChatMentionCandidatesObj, }; async function getSidebarThreadInfo( input: GetSidebarThreadInfoInput, ): Promise { - const { sourceMessage, loggedInUserInfo, getENSNames } = input; + const { + sourceMessage, + loggedInUserInfo, + getENSNames, + chatMentionCandidatesObj, + } = input; const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; if (threadCreatedFromMessage) { return threadCreatedFromMessage; @@ -62,11 +81,17 @@ } const { messageInfo, threadInfo } = sourceMessage; + const chatMentionCandidates = threadChatMentionCandidates( + threadInfo, + chatMentionCandidatesObj, + ); + return await createPendingSidebar({ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, loggedInUserInfo, - markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + markdownRules: getDefaultTextMessageRules(chatMentionCandidates) + .simpleMarkdownRules, getENSNames, }); } @@ -77,16 +102,24 @@ const loggedInUserInfo = useLoggedInUserInfo(); const navigateToThread = useNavigateToThread(); const cacheContext = React.useContext(ENSCacheContext); + const chatMentionCandidatesObj = useChatMentionCandidatesObj(); const { getENSNames } = cacheContext; return React.useCallback(async () => { const threadInfo = await getSidebarThreadInfo({ sourceMessage: item, loggedInUserInfo, getENSNames, + chatMentionCandidatesObj, }); invariant(threadInfo, 'threadInfo should be set'); navigateToThread({ threadInfo }); - }, [navigateToThread, item, loggedInUserInfo, getENSNames]); + }, [ + item, + loggedInUserInfo, + getENSNames, + chatMentionCandidatesObj, + 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, + useChatMentionCandidatesObj, +} from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { clusterEndHeight } from './chat-constants.js'; @@ -206,9 +209,15 @@ } = chatContext; const loggedInUserInfo = useLoggedInUserInfo(); + const chatMentionCandidatesObj = useChatMentionCandidatesObj(); const sidebarThreadInfo = React.useMemo( - () => getUnresolvedSidebarThreadInfo({ sourceMessage, loggedInUserInfo }), - [sourceMessage, loggedInUserInfo], + () => + getUnresolvedSidebarThreadInfo({ + sourceMessage, + loggedInUserInfo, + chatMentionCandidatesObj, + }), + [sourceMessage, loggedInUserInfo, chatMentionCandidatesObj], ); 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'); @@ -395,14 +401,11 @@ }; } -let defaultTextMessageRules = null; - -function getDefaultTextMessageRules(): MarkdownRules { - if (!defaultTextMessageRules) { - defaultTextMessageRules = textMessageRules([], false); - } - return defaultTextMessageRules; -} +const getDefaultTextMessageRules: ( + overrideDefaultChatMentionCandidates?: ChatMentionCandidates, +) => MarkdownRules = _memoize((overrideDefaultChatMentionCandidates = {}) => + textMessageRules([], overrideDefaultChatMentionCandidates, false), +); export { inlineMarkdownRules,