diff --git a/native/chat/inner-robotext-message.react.js b/native/chat/inner-robotext-message.react.js index f2f37cd0b..b2d924eb6 100644 --- a/native/chat/inner-robotext-message.react.js +++ b/native/chat/inner-robotext-message.react.js @@ -1,159 +1,159 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { Text, TouchableWithoutFeedback, View } from 'react-native'; import { threadInfoSelector } from 'lib/selectors/thread-selectors'; import { splitRobotext, parseRobotextEntity, robotextToRawString, } from 'lib/shared/message-utils'; import Markdown from '../markdown/markdown.react'; import { inlineMarkdownRules } from '../markdown/rules.react'; import { useSelector } from '../redux/redux-utils'; import { useOverlayStyles } from '../themes/colors'; import type { ChatRobotextMessageInfoItemWithHeight } from '../types/chat-types'; import { useNavigateToThread } from './message-list-types'; function dummyNodeForRobotextMessageHeightMeasurement( robotext: string, ): React.Element { return ( {robotextToRawString(robotext)} ); } type InnerRobotextMessageProps = { +item: ChatRobotextMessageInfoItemWithHeight, +onPress: () => void, +onLongPress?: () => void, }; function InnerRobotextMessage(props: InnerRobotextMessageProps): React.Node { const { item, onLongPress, onPress } = props; const activeTheme = useSelector(state => state.globalThemeInfo.activeTheme); const styles = useOverlayStyles(unboundStyles); const { messageInfo, robotext } = item; const { threadID } = messageInfo; const textParts = React.useMemo(() => { const robotextParts = splitRobotext(robotext); const result = []; let keyIndex = 0; for (const splitPart of robotextParts) { if (splitPart === '') { continue; } + const key = `text${keyIndex++}`; if (splitPart.charAt(0) !== '<') { const darkColor = activeTheme === 'dark'; - const key = `text${keyIndex++}`; result.push( {decodeURI(splitPart)} , ); continue; } const { rawText, entityType, id } = parseRobotextEntity(splitPart); if (entityType === 't' && id !== threadID) { - result.push(); + result.push(); } else if (entityType === 'c') { - result.push(); + result.push(); } else { result.push(rawText); } } return result; }, [robotext, activeTheme, threadID, styles.robotext]); const viewStyle = [styles.robotextContainer]; if (!__DEV__) { // We don't force view height in dev mode because we // want to measure it in Message to see if it's correct viewStyle.push({ height: item.contentHeight }); } return ( {textParts} ); } type ThreadEntityProps = { +id: string, +name: string, }; function ThreadEntity(props: ThreadEntityProps) { const threadID = props.id; const threadInfo = useSelector(state => threadInfoSelector(state)[threadID]); const styles = useOverlayStyles(unboundStyles); const navigateToThread = useNavigateToThread(); const onPressThread = React.useCallback(() => { invariant(threadInfo, 'onPressThread should have threadInfo'); navigateToThread({ threadInfo }); }, [threadInfo, navigateToThread]); if (!threadInfo) { return {props.name}; } return ( {props.name} ); } function ColorEntity(props: { +color: string }) { const colorStyle = { color: props.color }; return {props.color}; } const unboundStyles = { link: { color: 'link', }, robotextContainer: { paddingTop: 6, paddingBottom: 11, paddingHorizontal: 24, }, robotext: { color: 'listForegroundSecondaryLabel', fontFamily: 'Arial', fontSize: 15, textAlign: 'center', }, dummyRobotext: { fontFamily: 'Arial', fontSize: 15, textAlign: 'center', }, }; const MemoizedInnerRobotextMessage: React.ComponentType = React.memo( InnerRobotextMessage, ); export { dummyNodeForRobotextMessageHeightMeasurement, MemoizedInnerRobotextMessage as InnerRobotextMessage, }; diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js index 1be3dd898..8ec8abd16 100644 --- a/web/chat/robotext-message.react.js +++ b/web/chat/robotext-message.react.js @@ -1,170 +1,170 @@ // @flow import * as React from 'react'; import { useDispatch } from 'react-redux'; import { type RobotextChatMessageInfoItem } from 'lib/selectors/chat-selectors'; import { threadInfoSelector } from 'lib/selectors/thread-selectors'; import { splitRobotext, parseRobotextEntity } from 'lib/shared/message-utils'; import type { Dispatch } from 'lib/types/redux-types'; import { type ThreadInfo } from 'lib/types/thread-types'; import Markdown from '../markdown/markdown.react'; import { linkRules } from '../markdown/rules.react'; import { updateNavInfoActionType } from '../redux/action-types'; import { useSelector } from '../redux/redux-utils'; import { tooltipPositions, useMessageTooltip } from '../utils/tooltip-utils'; import InlineEngagement from './inline-engagement.react'; import css from './robotext-message.css'; const availableTooltipPositionsForRobotext = [ tooltipPositions.LEFT, tooltipPositions.LEFT_TOP, tooltipPositions.LEFT_BOTTOM, tooltipPositions.RIGHT, tooltipPositions.RIGHT_TOP, tooltipPositions.RIGHT_BOTTOM, ]; type BaseProps = { +item: RobotextChatMessageInfoItem, +threadInfo: ThreadInfo, }; type Props = { ...BaseProps, +onMouseLeave: ?() => mixed, +onMouseEnter: (event: SyntheticEvent) => mixed, }; class RobotextMessage extends React.PureComponent { render() { let inlineEngagement; if ( this.props.item.threadCreatedFromMessage || this.props.item.reactions.size > 0 ) { inlineEngagement = (
); } return (
{this.linkedRobotext()}
{inlineEngagement}
); } linkedRobotext() { const { item } = this.props; const { robotext } = item; const robotextParts = splitRobotext(robotext); const textParts = []; let keyIndex = 0; for (const splitPart of robotextParts) { if (splitPart === '') { continue; } + const key = `text${keyIndex++}`; if (splitPart.charAt(0) !== '<') { - const key = `text${keyIndex++}`; textParts.push( {decodeURI(splitPart)} , ); continue; } const { rawText, entityType, id } = parseRobotextEntity(splitPart); if (entityType === 't' && id !== item.messageInfo.threadID) { - textParts.push(); + textParts.push(); } else if (entityType === 'c') { - textParts.push(); + textParts.push(); } else { textParts.push(rawText); } } return textParts; } } type BaseInnerThreadEntityProps = { +id: string, +name: string, }; type InnerThreadEntityProps = { ...BaseInnerThreadEntityProps, +threadInfo: ThreadInfo, +dispatch: Dispatch, }; class InnerThreadEntity extends React.PureComponent { render() { return {this.props.name}; } onClickThread = (event: SyntheticEvent) => { event.preventDefault(); const id = this.props.id; this.props.dispatch({ type: updateNavInfoActionType, payload: { activeChatThreadID: id, }, }); }; } const ThreadEntity = React.memo( function ConnectedInnerThreadEntity(props: BaseInnerThreadEntityProps) { const { id } = props; const threadInfo = useSelector(state => threadInfoSelector(state)[id]); const dispatch = useDispatch(); return ( ); }, ); function ColorEntity(props: { color: string }) { const colorStyle = { color: props.color }; return {props.color}; } const ConnectedRobotextMessage: React.ComponentType = React.memo( function ConnectedRobotextMessage(props) { const { item, threadInfo } = props; const { onMouseLeave, onMouseEnter } = useMessageTooltip({ item, threadInfo, availablePositions: availableTooltipPositionsForRobotext, }); return ( ); }, ); export default ConnectedRobotextMessage;